如何最好地测试一项服务,以确保谁的影响被残缺的依赖所覆盖

时间:2019-09-19 18:01:17

标签: unit-testing tdd

首先,我的示例在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类型的交易,但是那时候我将进入测试的反模式,即“测试实现,而不是功能”。

那么,我如何才能最好地解决这个问题,并且最好的测试方法是什么?

1 个答案:

答案 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());
}

中,正常会更改实现的设计,使其更适合您的测试。