Mockito:嘲弄"Blackbox"依赖

IAm*_*aja 11 java unit-testing mocking mockito

所以我被要求为我们的开发团队阅读模拟和BDD,并玩嘲笑,以便改进我们现有的一些单元测试(作为实验).

我最终选择与Mockito一起出于多种原因(有些原因超出了我的控制范围),但是因为它支持对模拟不适合的实例进行存根和模拟.

我整天都在学习Mockito,嘲笑(一般)和BDD.现在我准备深入挖掘并开始增强我们的单元测试.

所以我们有一个叫做WebAdaptor有一个run()方法的类:

public class WebAdaptor {

    private Subscriber subscriber;

    public void run() {

        subscriber = new Subscriber();
        subscriber.init();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意:我没有办法修改此代码(出于此问题范围之外的原因!).因此,我无法为其添加setter方法Subscriber,因此它可以被认为是我内部无法访问的"黑盒子" WebAdaptor.

我想编写一个包含Mockito模拟的单元测试,并使用该模拟来调用verify执行的WebAdaptor::run()原因Subscriber::init().

所以这就是我到目前为止(内部WebAdaptorUnitTest):

@Test
public void runShouldInvokeSubscriberInit() {

    // Given
    Subscriber mockSubscriber = mock(Subscriber.class);
    WebAdaptor adaptor = new WebAdaptor();

    // When
    adaptor.run();

    // Then
    verify(mockSubscriber).init();
}
Run Code Online (Sandbox Code Playgroud)

当我运行这个测试,实际的Subscriber::init()方法被执行(我可以从控制台输出告诉我的本地系统上生成的文件看到),没有mockSubscriber,这不应该做(或退货)任何东西.

我已经检查并重新检查:initpublic,既不是staticfinal,并返回void.根据文档,Mockito应该没有问题嘲笑这个对象.

所以它让我思考:我是否需要明确地将其mockSubscriberadaptor?如果是这种情况,那么通常情况下,以下情况通常会解决它:

adaptor.setSubscriber(mockSubscriber);
Run Code Online (Sandbox Code Playgroud)

但由于我不能添加任何这样的二传手(请阅读我上面的注释),我不知道如何强迫这样的关联.所以,有几个非常密切相关的问题:

  • 任何人都可以确认我已正确设置测试(使用Mockito API)吗?
  • 我怀疑失踪的二传手是否正确?(我是否需要通过setter关联这些对象?)
  • 如果我的上述怀疑是真的,我无法修改WebAdaptor,我的处置是否有任何规避?

提前致谢!

Dav*_*d V 10

您需要将模拟注入您正在测试的类中.您无需访问Subscriber.mockito和其他模拟框架的帮助方式是您不需要访问与之交互的对象.但是,您需要一种方法将模拟对象放入您正在测试的类中.

public class WebAdaptor {

    public WebAdaptor(Subscriber subscriber) { /* Added a new constructor */
       this.subscriber = subscriber;
    }

    private Subscriber subscriber;

    public void run() {
        subscriber.init();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以在模拟上验证您的交互,而不是在真实对象上.

@Test
public void runShouldInvokeSubscriberInit() {

    // Given
    Subscriber mockSubscriber = mock(Subscriber.class);
    WebAdaptor adaptor = new WebAdaptor(mockSubscriber);  // Use the new constructor

    // When
    adaptor.run();

    // Then
    verify(mockSubscriber).init();
}
Run Code Online (Sandbox Code Playgroud)

如果将订阅服务器添加到构造函数不是正确的方法,您还可以考虑使用工厂允许WebAdaptor从您控制的工厂实例化新的订阅服务器对象.然后,您可以模拟工厂提供模拟订阅服务器.

  • 为了使您的WebAdaptor类使用现有代码,您可能还希望拥有一个调用新构造函数的无参数构造函数.然后,类的现有非测试用法可以使用no-arg构造函数.所以新构造函数将是`public WebAdaptor(){this(new Subscriber());}`.此外,具有Subscriber参数的构造函数应该是package-private. (2认同)

ste*_*ase 5

如果您不想更改生产代码并仍然能够模拟Subscriber类的功能,那么您应该查看PowerMock.它与Mockito一起工作正常,并允许您模拟新对象的创建.

Subscriber mockSubscriber = mock(Subscriber.class);
whenNew(Subscriber.class).withNoArguments().thenReturn(mockSubscriber);
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅PowerMock框架的文档.