问题描述
我有一个可用于持久存储用户的Doctrine存储库类,我不想检查实体是否真的持久存在,我只想知道在这种情况下该怎么做:
测试具有返回值的存储库方法很容易。但是在这种情况下,我无事可做,我想覆盖100%的代码,而不制作不安全的代码,这些代码可能会像使用@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);
}
}
还有一个测试类:
<?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()
方法返回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);
}
}
您甚至可以更进一步,并使用回调约束来验证是否在创建持久调用之前设置了创建日期。但是,然后,您将在测试中逐行检查实现。这样一来,人们的测试就会一直中断。
那么,该怎么办呢?关注用户存储库的目的:如果放入某些内容,则应该可以将其取出。但是,这要求您使用实际的实体管理器。但是您写道,您不想检查该实体是否确实存在。在那种情况下,我宁愿不写任何测试,而不是上面给出的示例。