首先,我的示例在php中,但这不是php问题,只是有关测试最佳做法的问题
所以我有要测试的功能
public function createNewTodo(CreateTodoQuery $query): TodoResponseObject
{
$new_todo = TodoFactory::createNew($query->getUserId(), $query->getTitle())
->withDescription($query->getDescription());
$new_todo = $this->todo_repository->save($new_todo);
return TodoResponseObject::fromDomain($new_todo);
}
为了测试此功能,我将需要解决依赖项(todo_repository
)。我想进行一个测试,断言我得到的是TodoResponseObject
的实例。很简单
现在具有挑战性的一点:我想断言要使用查询中设置的参数创建的todo对象。由于将要存根todo_repository
,因此我实际上无法做到这一点,因为我的测试仅会确定配置存根要返回的值。我可以做类似assertCalledWith
类型的交易,但是那时候我将进入测试的反模式,即“测试实现,而不是功能”。
那么,我如何才能最好地解决这个问题,并且最好的测试方法是什么?
答案 0 :(得分:0)
请参见Sandi Metz,Magic Tricks of Testing
如果您要测试代码是否将正确的消息发送到了工厂,那么通常的答案是使用test double(模拟或间谍)来跟踪邮件发送给它,以便您以后可以对其进行验证。
这可能需要更改代码的设计,以便您可以更轻松地用一种工厂实现替换另一种工厂实现(例如,通过将装饰器包装在“实际”工厂方法周围)。
另一种可能性是将工厂调用分为一个单独的方法,并测试该方法对参数的处理
public function createTodo(CreateTodoQuery $query) {
return TodoFactory::createNew($query->getUserId(), $query->getTitle())
->withDescription($query->getDescription());
}
在tdd中,正常会更改实现的设计,使其更适合您的测试。