3

我是测试新手,我不确定我是否以正确的方式进行:

我不想对特定的类进行单元测试,而是对从我的 ioc 容器中解决的任何类进行单元测试。在 ioc 容器中,我将接口绑定到具体类,如下所示:

示例(我正在使用 Laravel 5):

// in a service provider
public function register(){ 

    $this->app->bind('FooInterface', function() { 
        return new SomeConcreteFoo; 
    }); 
 }

然后我想编写单元测试,FooInterface而不是SomeConcreteFoo稍后可以与其他类交换。

我想这样做的原因是,在我看来,相关测试应该针对我的 ioc 容器返回的任何内容,因为这就是我将在应用程序中使用的内容。在我看来,测试应该在接口级别完成,因为这是我定义应用程序其余部分对我的班级的期望的地方。

我很难找到有关如何执行此操作的任何信息,这表明我可能会以错误的方式思考这个问题。例如,也许我想要完成的更像是集成测试而不是单元测试。

所以第一个问题是:我是否正在考虑以正确的方式进行测试?如果我不是 - 你对替代测试路径的最佳实践有什么建议吗?

第二个问题:如果我的想法是正确的 - 我如何设置 phpspec 以使用 Laravel IOC 容器,以便我可以针对 IOC 返回的任何内容进行测试..

4

1 回答 1

2

我不想对特定的类进行单元测试,而是对从我的 ioc 容器中解决的任何类进行单元测试。在 ioc 容器中,我将我的接口绑定到具体的类,就像这样 [...]

这不是单元测试的编写方式。单元测试是关于孤立地描述类行为,因此实际创建的唯一真实对象是被测类(有时是简单的值对象)。

然后我想针对 FooInterface 而不是 SomeConcreteFoo 编写单元测试,稍后可以将其与其他类交换。

这确实是您应该编写单元测试的方式。更喜欢协作者的界面。

每个模拟框架都支持这个特性,并且会为你创建测试替身,而不是强迫你提供特定的实现。

class BarSpec extends ObjectBehavior
{
    function it_does_amazing_things(FooInterface $foo)
    {
        $results = ['a', 'b', 'c'];

        $foo->find('something')->willReturn($results);

        $this->findMeSometing()->shouldReturn($results);
    }
}

在这个特定的示例中,PhpSpec 将使用 Prophecy(它的模拟框架)创建一个测试替身并将其FooInterface注入示例方法。你对这个对象做什么决定了它是假的、存根还是模拟。

我想这样做的原因是,在我看来,相关测试应该针对我的 ioc 容器返回的任何内容,因为这就是我将在应用程序中使用的内容。

如上所述,单元测试关注单个类的行为。它的合作者通常是伪造的。这有几个原因。其中之一是速度。另一个是反馈。如果测试失败,我们将获得关于哪个班级被打破的明确反馈。如果您要创建所有协作者,而不是使用测试替身,那么一个错误可能会使您的整个测试套件变红。我什至不会提及维护和创建所有需要的对象有多么困难(尽管容器在这里可以提供帮助)。

请记住,编写单元测试更多的是设计活动,而不是测试活动。

例如,也许我想要完成的更像是集成测试而不是单元测试。

的确。阅读有关测试金字塔的更多信息。您的大多数测试应该是单元测试。然后,您应该进行一些集成和验收测试,这些测试将同时运行多个类。您想要比集成测试更多的单元测试的原因是后者更脆弱,更难维护/更改它们。

使用 PHPUnit 进行集成测试。PhpSpec 不是这项工作的正确工具。PhpSpec 非常适合设计您的类(编写单元测试),特别是如果您先进行测试。

第二个问题:如果我的想法是正确的 - 我如何设置 phpspec 以使用 Laravel IOC 容器,以便我可以针对 IOC 返回的任何内容进行测试..

你没有。您可以考虑在集成测试中使用容器。

一些阅读:

于 2015-02-02T00:39:52.377 回答