Unit testing [PHPUnit],[Symfony]:测试该实体是否保存在数据库中
我的考试有问题。我学习如何编写phpunit测试,以及如何模拟对象、服务等。。我的ProductService上有以下方法:Unit testing [PHPUnit],[Symfony]:测试该实体是否保存在数据库中,unit-testing,symfony,mocking,phpunit,symfony4,Unit Testing,Symfony,Mocking,Phpunit,Symfony4,我的考试有问题。我学习如何编写phpunit测试,以及如何模拟对象、服务等。。我的ProductService上有以下方法: <?php namespace App\Service; use App\Entity\Product; use App\Repository\ProductRepository; use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\O
<?php
namespace App\Service;
use App\Entity\Product;
use App\Repository\ProductRepository;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\ORMException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Validator\Validator\ValidatorInterface;
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 App\Entity;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
*/
class Product
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank()
*/
private $name;
/**
* @ORM\Column(type="integer")
* @Assert\NotBlank()
*/
private $quantity;
/**
* @Gedmo\Mapping\Annotation\Timestampable(on="create")
* @ORM\Column(type="datetime")
*/
private $createdAt;
/**
* @Gedmo\Mapping\Annotation\Timestampable(on="update")
* @ORM\Column(type="datetime")
*/
private $updatedAt;
/**
* @ORM\Column(type="string")
* @Assert\NotBlank()
*/
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;
}
}
首先,在这个测试中,当你模拟一个方法时,原来的方法已经不存在了。在您的例子中,您可以用以下内容替换
ProductService::createProduct
:
// This is your mock
class ProductService
{
// ...
public function createProduct($productData)
{
return $this;
}
}
你的测试没有检查任何东西
如果您想测试真正的功能,那么
namespace App\Tests\Service;
use App\Repository\ProductRepository;
use App\Service\ProductService;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Validator\Validator\ValidatorInterface;
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);
}
}
您好,谢谢您的回答:)我检查了您的代码,第26行有错误,它是$productRepository,错误:错误:调用上的成员函数get()null@PawelC实际上,您也可以模拟存储库
productRepository=$this->createMock(productRepository::class)
;但是您将无法执行最后一次断言更改这一行,现在我对第28行有问题,它是$entity manager,当我将这一行更改为$this->createMock(EntityManager::class)
i have errorPHP致命错误:类Mock_ValidatorInterface_b607e347包含6个抽象方法,因此必须声明为抽象的
现在我又犯了一个错误,请查看我的第一篇帖子。我想这不是我的问题phpunit@PawelC检查产品实体注释中是否存在以下行:@ORM\entity(repositoryClass=“App\Repository\ProductRepository”)
<?php
namespace App\Repository;
use App\Entity\Product;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;
class ProductRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Product::class);
}
}
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: 'App\Entity'
alias: App
// This is your mock
class ProductService
{
// ...
public function createProduct($productData)
{
return $this;
}
}
namespace App\Tests\Service;
use App\Repository\ProductRepository;
use App\Service\ProductService;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Validator\Validator\ValidatorInterface;
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);
}
}