[PHPUnit],[Symfony]:测试实体是否保存在数据库中



我的测试有问题。我学习了如何编写phpunit测试,以及如何模拟对象、服务等

<?php
namespace AppService;
use AppEntityProduct;
use AppRepositoryProductRepository;
use DoctrineORMEntityManager;
use DoctrineORMEntityManagerInterface;
use DoctrineORMORMException;
use SymfonyComponentHttpKernelExceptionNotFoundHttpException;
use SymfonyComponentValidatorValidatorValidatorInterface;
class ProductService
{
/**
* @var ProductRepository
*/
private $productRepository;
/**
* @var EntityManager
*/
private $entityManager;
/**
* @var ValidatorInterface
*/
private $validator;
/**
* ProductService constructor.
* @param ProductRepository $productRepository
* @param EntityManagerInterface $entityManager
* @param ValidatorInterface $validator
*/
public function __construct(ProductRepository $productRepository, EntityManagerInterface $entityManager, ValidatorInterface $validator)
{
$this->productRepository = $productRepository;
$this->entityManager = $entityManager;
$this->validator = $validator;
}
/**
* @param $productData
* @return Product|string
*/
public function createProduct($productData)
{
$name = $productData['name'];
$quantity = $productData['quantity'];
$sku = $productData['sku'];
$product = new Product();
$product->setName($name);
$product->setQuantity($quantity);
$product->setProductSerial($sku);
$errors = $this->validator->validate($product);
if (count($errors) > 0) {
$errorsString = (string)$errors;
return $errorsString;
}
try {
$this->entityManager->persist($product);
$this->entityManager->flush();
return $product;
} catch (Exception $ex) {
return $ex->getMessage();
}
}
}

我写了这个测试:

<?php
namespace AppTestsService;
use AppEntityProduct;
use AppRepositoryProductRepository;
use AppServiceProductService;
use DoctrineCommonPersistenceObjectRepository;
use PHPUnitFrameworkTestCase;
class ProductServiceTest extends TestCase
{
/**
* Create product test
*/
public function testCreateProduct()
{
$product = new Product();
$product->setName('tester');
$product->setQuantity(2);
$product->setProductSerial('Examplecode');
$productService = $this->createMock(ProductService::class);
$productService->method('createProduct')->will($this->returnSelf());
$this->assertSame($productService, $productService->createProduct($product));
}
}

当我运行phpunit测试时,我总是成功的,但我的数据库是空的。我如何才能确保测试工作正常?哪些值得修复,哪些不值得修复?我想让测试的启动产生结果,例如,向测试数据库中添加记录,但我不知道如何做到这一点,也不知道如何正确地模拟它。我使用phpunit+Symfony 4。

我曾经写过测试,但那些要求端点API的测试,在这里我想测试没有端点的服务和存储库。

我想学习如何测试和模拟网站,存储库,各种类等

当我申请答案时,我有:

PHPUnit 7.5.17 by Sebastian Bergmann and contributors.
Testing Project Test Suite
?[31;1mE?[0m                                                                   1 / 1 (100%)
Time: 542 ms, Memory: 10.00 MB
There was 1 error:
1) AppTestsServiceProductServiceTest::testCreateProduct
DoctrineCommonPersistenceMappingMappingException: The class 'AppRepositoryProductRepository' was not found in the chain configured namespaces AppEntity, GesdinetJWTRefreshTokenBundleEntity
D:warehouse-management-apivendordoctrinepersistencelibDoctrineCommonPersistenceMappingMappingException.php:22
D:warehouse-management-apivendordoctrinepersistencelibDoctrineCommonPersistenceMappingDriverMappingDriverChain.php:87
D:warehouse-management-apivendordoctrineormlibDoctrineORMMappingClassMetadataFactory.php:151
D:warehouse-management-apivendordoctrinepersistencelibDoctrineCommonPersistenceMappingAbstractClassMetadataFactory.php:304
D:warehouse-management-apivendordoctrineormlibDoctrineORMMappingClassMetadataFactory.php:78
D:warehouse-management-apivendordoctrinepersistencelibDoctrineCommonPersistenceMappingAbstractClassMetadataFactory.php:183
D:warehouse-management-apivendordoctrineormlibDoctrineORMEntityManager.php:283
D:warehouse-management-apivendordoctrinedoctrine-bundleRepositoryContainerRepositoryFactory.php:44
D:warehouse-management-apivendordoctrineormlibDoctrineORMEntityManager.php:713
D:warehouse-management-apivendordoctrinepersistencelibDoctrineCommonPersistenceAbstractManagerRegistry.php:215
D:warehouse-management-apitestsServiceProductServiceTest.php:28
?[37;41mERRORS!?[0m
?[37;41mTests: 1?[0m?[37;41m, Assertions: 0?[0m?[37;41m, Errors: 1?[0m?[37;41m.?[0m

我的产品实体

<?php
namespace AppEntity;
use DateTime;
use DoctrineORMMapping as ORM;
use SymfonyComponentValidatorConstraints as Assert;
/**
* @ORMEntity(repositoryClass="AppRepositoryProductRepository")
*/
class Product
{
/**
* @ORMId()
* @ORMGeneratedValue()
* @ORMColumn(type="integer")
*/
private $id;
/**
* @ORMColumn(type="string", length=255)
* @AssertNotBlank()
*/
private $name;
/**
* @ORMColumn(type="integer")
* @AssertNotBlank()
*/
private $quantity;
/**
* @GedmoMappingAnnotationTimestampable(on="create")
* @ORMColumn(type="datetime")
*/
private $createdAt;
/**
* @GedmoMappingAnnotationTimestampable(on="update")
* @ORMColumn(type="datetime")
*/
private $updatedAt;
/**
* @ORMColumn(type="string")
* @AssertNotBlank()
*/
private $product_serial;

public function __construct() {
$this->setCreatedAt(new DateTime());
$this->setUpdatedAt();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getQuantity(): ?int
{
return $this->quantity;
}
public function setQuantity(int $quantity): self
{
$this->quantity = $quantity;
return $this;
}
public function getCreatedAt(): ?DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(): self
{
$this->updatedAt = new DateTime();
return $this;
}
public function getProductSerial(): ?string
{
return $this->product_serial;
}
public function setProductSerial(string $product_serial): self
{
$this->product_serial = $product_serial;
return $this;
}
}

产品存储库

<?php
namespace AppRepository;
use AppEntityProduct;
use DoctrineBundleDoctrineBundleRepositoryServiceEntityRepository;
use DoctrineCommonPersistenceManagerRegistry;
class ProductRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Product::class);
}
}

doctrine.yaml

doctrine:
dbal:
# configure these for your database server
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
url: '%env(resolve:DATABASE_URL)%'
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'AppEntity'
alias: App

首先,当您模拟一个方法时,在这个测试中,原始方法已经不存在了。在您的情况下,您可以用以下内容替换ProductService::createProduct

// This is your mock
class ProductService 
{
// ...
public function createProduct($productData)
{
return $this;
}
}

你的测试没有检查任何东西。

如果你想测试真正的功能,那么

namespace AppTestsService;
use AppRepositoryProductRepository;
use AppServiceProductService;
use SymfonyBundleFrameworkBundleTestKernelTestCase;
use SymfonyComponentValidatorValidatorValidatorInterface;
class ProductServiceTest extends KernelTestCase
{
/**
* Create product test
*/
public function testCreateProduct(): void
{
// We load the kernel here (and $container)
self::bootKernel();
$productData = [
'name' => 'foo',
'quantity' => 1,
'sku' => 'bar',
];
$productRepository = static::$container->get('doctrine')->getRepository(ProductRepository::class);
$entityManager = static::$container->get('doctrine')->getManager();
// Here we mock the validator.
$validator = $this->getMockBuilder(ValidatorInterface::class)
->disableOriginalConstructor()
->setMethods(['validate'])
->getMock();
$validator->expects($this->once())
->method('validate')
->willReturn(null);
$productService = new ProductService($productRepository, $entityManager, $validator);
$productFromMethod = $productService->createProduct($productData);
// Here is you assertions:
$this->assertSame($productData['name'], $productFromMethod->getName());
$this->assertSame($productData['quantity'], $productFromMethod->getQuantity());
$this->assertSame($productData['sku'], $productFromMethod->getSku());
$productFromDB = $productRepository->findOneBy(['name' => $productData['name']]);
// Here we test that product in DB and returned product are same
$this->assertSame($productFromDB, $productFromMethod);
}
}

最新更新