如果仍然可以模拟对象,为什么服务定位器不利于测试?

Why Service Locator is bad for testing if one can still mock objects?

每个人都知道使用服务定位器的代码很难测试,而应该使用依赖注入。

但是如果我们仍然可以轻松地模拟每个对象,为什么服务定位器很难测试呢?

考虑这个例子(用PHP写的,但它可以是任何语言)

// method we want to test that has a dependency 
public myFunction() {
    $someDependency = Registry::getService('Dependency');

    // do something with the dependendcy
    $someDependency->doSomething();

    return true;
}

如果我们想测试这段代码,我们可以简单地模拟我们的对象 "Dependency",示例:

 function testMyFunction() {
        $mock = \Mockery::mock('Dependency');
        $mock->shouldReceive('doSomething')->once();

        Registry::set('Dependency', $mock); // set the double

        $workerObject = new MyClass;
        $this->assertTrue( $workerObject->myFunction() );
 }

这段代码不是可测试的吗?为什么服务定位器在这种情况下不好?

请注意,我们都知道服务定位器有多糟糕,因为它隐藏了依赖性和紫罗兰色 SOLID 原则。但在这种情况下,我只是指测试方面。

根据我的经验,这主要是因为它弄乱了全局状态。

在测试 A 的注册表中设置一些东西,有一天它会搞砸测试 B,你将花费一整天的时间来调试它。

当然,如果每次测试都完全重置所有内容,那么您可以将风险降至最低。但它会使您的测试套件变慢。同样,YMMV,但是例如在我正在处理的一个大项目中这是一场噩梦。

Note that we all know how bad a Service locator because it hides dependency and violets SOLID principles. But in this case i am simply referring to the testing aspect.

我发现很难测试隐藏其依赖关系的东西。必须通过所有代码才能知道我必须模拟什么,这很无聊而且浪费时间。

通过依赖注入,我只需输入 new ClassToTest(_,IDE 会立即显示需要哪些依赖项。

Everyone knows that code that uses Service Locator is hard to test while Dependency Injection should be used instead.

我不知道...

Service Locator is an anti-pattern 的原因不是因为它使代码难以测试(事实并非如此),而是因为它难以维护

服务定位器破坏了封装,因为您可以在代码中的任何地方使用它,如果不通读所有可能使用它的代码,客户端就没有机会检测到这一点.

依赖注入是更好的选择,因为它solves the same problems with fewer disadvantages.