【问题标题】:How to test with mocks when using the Service Locator pattern?使用服务定位器模式时如何使用模拟进行测试?
【发布时间】:2014-06-21 01:24:41
【问题描述】:

前言:我的默认操作模式是使用 IoC 容器和构造函数注入。这使得使用模拟依赖项进行测试变得微不足道。

我开始开发一个 IntelliJ 插件,我想利用控制反转。由于这是一个插件,因此实际上没有容器选项(对吗?)所以我想我需要使用服务定位器模式。

如何使用带有 Service Locator 模式的 mock 进行测试?

我能想到的最好的方法是为我的定位器使用一个接口,使用静态 getter 在每个服务的默认构造函数中设置它,并拥有一个 setter,以便我可以设置一个模拟定位器。它看起来像这样:

public class MyService {
    private IServiceLocator locator;

    public MyService() {
        setLocator(ServiceLocator.locator());
    }

    public void setLocator(IServiceLocator locator) {
        this.locator = locator;
    }
}

现在我可以模拟 IServiceLocator 并在我的测试中将其设置为 MyService。然后我可以期待像locator.dependency1() 这样的调用并让它返回一个模拟的依赖项。

我对这种方法的主要问题是定位器设置器仅用于支持测试。 有更好的方法吗?

【问题讨论】:

    标签: java unit-testing intellij-idea intellij-plugin service-locator


    【解决方案1】:

    首先,我建议阅读出色的“有效地使用遗留代码”,其中包含大量用于处理此类问题的模式。尽管您正在编写新代码,但您会受到一些与旧代码相同的限制。

    为此,一种更简单的方法可能是提供第二个受保护的构造函数,该构造函数显式接受您的依赖项,并让无参数构造函数使用您想要的默认值。所以类似于以下内容:

     public class MyService {
        private Dependency1 dep1;
        private Dependency2 dep2;
    
        protected MyService(Dependency1 dep1, Dependency2 dep2) {
            this.dep1 = dep1;
            this.dep2 = dep2;
        }
    
        public MyService() {
             this(new ConcreteDependency1(), new ConcreteDependency2());
        }
    }
    

    您还可以添加注释以明确这是用于测试,即Guava's @VisibleForTesting

    【讨论】:

      【解决方案2】:

      您可以按照您描述的方式进行操作。我想到了其他选择:

      您可以对服务定位器字段使用包私有访问

      现在,如果您将测试类与服务放在同一个包中 - 它可以直接操作测试类中的字段 - 所以很容易模拟服务定位器。

      您可以使用测试/模拟库的功能来注入服务定位器

      例如 Mockito (https://code.google.com/p/mockito/) 可以通过两种方式注入私有字段:

      • Whitebox class - 但这不是最好的主意,因为您必须知道要模拟的字段名称(更改字段名称会破坏测试),并且您需要手动执行 Withebox.setInternalState 方法
      • @InjectMocks 注释 - 您创建使用 @Mock 注释注释的服务定位器字段,并使用 @InjectMocks 注释的服务字段,mockito 将使用服务定位器字段并将其自动注入服务。

      可以使用不依赖容器的依赖注入机制

      例如查看 Google Guice 库:https://code.google.com/p/google-guice/

      您可以使用“手动”依赖注入

      DI 是模式 - DI 容器/框架使这种模式易于实现,但您始终可以自己使用工厂类来实现(但需要更多时间)。下面是关于 DI 的精彩讨论,涵盖“手动”DI:https://www.youtube.com/watch?v=RlfLCWKxHJ0

      很难说哪个选项最适合您。如果您想坚持使用服务定位器 - 我会推荐 Mockito。如果你想要 DI - 我会推荐 Google Guice。就个人而言,我认为服务定位器更像是反模式。

      【讨论】:

        猜你喜欢
        • 2013-04-01
        • 2023-03-09
        • 1970-01-01
        • 1970-01-01
        • 2021-03-09
        • 1970-01-01
        • 1970-01-01
        • 2013-10-16
        • 2011-03-12
        相关资源
        最近更新 更多