PHPUnit:如何测试 returns 无效的 Doctrine Repository 方法?
PHPUnit: How to test Doctrine Repository method that returns void?
我有一个 Doctrine 存储库 class 可以用来持久化一个用户,我不想检查实体是否真的被持久化了,我只是想知道在这方面该做什么情况:
测试具有 return 值 的存储库方法很容易。但在这种情况下,我无事可做,我想覆盖 100% 的代码,而不是像 use @addToAssertionCount
.
这样会破坏的不安全代码
<?php
namespace Domain\Repository;
use DateTime;
use Domain\Entity\User;
use Domain\Repository\Interfaces\UserRepositoryInterface;
class UserRepository extends Repository implements UserRepositoryInterface
{
public function create(User $user): void
{
$user->setCreatedAt(new DateTime('now'));
$this->getEntityManager()->persist($user);
}
}
并对其进行测试 class:
<?php
namespace Domain\Repository;
use Doctrine\ORM\EntityManager;
use Domain\Entity\User;
use PHPUnit\Framework\TestCase;
class UserRepositoryTest extends TestCase
{
private UserRepository $sut;
public function setUp(): void
{
$entity_manager = $this->createMock(EntityManager::class);
$this->sut = new UserRepository($entity_manager);
}
public function test_assert_create(): void
{
$user = $this->createMock(User::class);
$this->sut->create($user);
// What to assert??
}
}
在这一点上,我什至不知道要断言什么,一旦 persist()
方法 returns void
,我无法模拟。
专注于 100% 的代码覆盖率并不是一个好主意,并且会鼓励编写几乎没有价值的测试。那是什么意思? create
方法有两个副作用:它更改了用户的创建日期并将其持久化。你可以这样测试它:
final class UserRepositoryTest extends TestCase
{
/**
* @var EntityManager&MockObject
*/
private EntityManager $entityManager;
private UserRepository $sut;
public function setUp(): void
{
$this->entityManager = $this->createMock(EntityManager::class);
$this->sut = new UserRepository($this->entityManager);
}
public function test_create_should_persist_entity(): void
{
$user = new User();
$user->setCreatedAt(new DateTime('2000-01-01 12:15:30'));
// validate that persist call was made
$this->entityManager->expects(self::once())
->method('persist')
->with($user);
$this->sut->create($user);
// validate that creation date was set
self::assertEqualsWithDelta(new DateTime('now'), $user->getCreatedAt(), 3);
}
}
您甚至可以更进一步,验证创建日期是否在使用回调约束进行持久调用之前设置。但是,您几乎是在测试中逐行检查实现。这就是人们如何结束总是失败的测试。
那么,该怎么做呢?关注用户存储库的目的:如果你把东西放进去,你应该能够把它取出来。但是,这需要您使用实际的实体管理器。但是您写道,您不想检查该实体是否确实持久存在。在那种情况下,我宁愿不写测试也不愿写我上面给出的例子。
我有一个 Doctrine 存储库 class 可以用来持久化一个用户,我不想检查实体是否真的被持久化了,我只是想知道在这方面该做什么情况:
测试具有 return 值 的存储库方法很容易。但在这种情况下,我无事可做,我想覆盖 100% 的代码,而不是像 use @addToAssertionCount
.
<?php
namespace Domain\Repository;
use DateTime;
use Domain\Entity\User;
use Domain\Repository\Interfaces\UserRepositoryInterface;
class UserRepository extends Repository implements UserRepositoryInterface
{
public function create(User $user): void
{
$user->setCreatedAt(new DateTime('now'));
$this->getEntityManager()->persist($user);
}
}
并对其进行测试 class:
<?php
namespace Domain\Repository;
use Doctrine\ORM\EntityManager;
use Domain\Entity\User;
use PHPUnit\Framework\TestCase;
class UserRepositoryTest extends TestCase
{
private UserRepository $sut;
public function setUp(): void
{
$entity_manager = $this->createMock(EntityManager::class);
$this->sut = new UserRepository($entity_manager);
}
public function test_assert_create(): void
{
$user = $this->createMock(User::class);
$this->sut->create($user);
// What to assert??
}
}
在这一点上,我什至不知道要断言什么,一旦 persist()
方法 returns void
,我无法模拟。
专注于 100% 的代码覆盖率并不是一个好主意,并且会鼓励编写几乎没有价值的测试。那是什么意思? create
方法有两个副作用:它更改了用户的创建日期并将其持久化。你可以这样测试它:
final class UserRepositoryTest extends TestCase
{
/**
* @var EntityManager&MockObject
*/
private EntityManager $entityManager;
private UserRepository $sut;
public function setUp(): void
{
$this->entityManager = $this->createMock(EntityManager::class);
$this->sut = new UserRepository($this->entityManager);
}
public function test_create_should_persist_entity(): void
{
$user = new User();
$user->setCreatedAt(new DateTime('2000-01-01 12:15:30'));
// validate that persist call was made
$this->entityManager->expects(self::once())
->method('persist')
->with($user);
$this->sut->create($user);
// validate that creation date was set
self::assertEqualsWithDelta(new DateTime('now'), $user->getCreatedAt(), 3);
}
}
您甚至可以更进一步,验证创建日期是否在使用回调约束进行持久调用之前设置。但是,您几乎是在测试中逐行检查实现。这就是人们如何结束总是失败的测试。
那么,该怎么做呢?关注用户存储库的目的:如果你把东西放进去,你应该能够把它取出来。但是,这需要您使用实际的实体管理器。但是您写道,您不想检查该实体是否确实持久存在。在那种情况下,我宁愿不写测试也不愿写我上面给出的例子。