用mockito嘲笑一个单身人士 [英] Mocking a singleton with mockito

查看:110
本文介绍了用mockito嘲笑一个单身人士的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要测试一些遗留代码,它在方法调用中使用单例。测试的目的是确保clas sunder测试调用单例方法。
我在SO上看到过类似的问题,但是所有答案都需要其他依赖项(不同的测试框架) - 我不幸仅限于使用Mockito和JUnit,但是这种流行的框架应该是完全可能的。

I need to test some legacy code, which uses a singleton in a a method call. The purpose of the test is to ensure that the clas sunder test makes a call to singletons method. I have seen similar questions on SO, but all the answers require other dependencies (different test frameworks) - I'm unfortunately limited to using Mockito and JUnit, but this should be perfectly possible with such popular framework.

单身人士:

public class FormatterService {

    private static FormatterService INSTANCE;

    private FormatterService() {
    }

    public static FormatterService getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new FormatterService();
        }
        return INSTANCE;
    }

    public String formatTachoIcon() {
        return "URL";
    }

}

被测试的课程:

public class DriverSnapshotHandler {

    public String getImageURL() {
        return FormatterService.getInstance().formatTachoIcon();
    }

}

单元测试:

public class TestDriverSnapshotHandler {

    private FormatterService formatter;

    @Before
    public void setUp() {

        formatter = mock(FormatterService.class);

        when(FormatterService.getInstance()).thenReturn(formatter);

        when(formatter.formatTachoIcon()).thenReturn("MockedURL");

    }

    @Test
    public void testFormatterServiceIsCalled() {

        DriverSnapshotHandler handler = new DriverSnapshotHandler();
        handler.getImageURL();

        verify(formatter, atLeastOnce()).formatTachoIcon();

    }

}

这个想法是配置可怕的单例的预期行为,因为被测试的类将调用它的getInstance,然后调用formatTachoIcon方法。不幸的是,这失败并显示错误消息:

The idea was to configure the expected behaviour of the dreaded singleton, since the class under test will call it's getInstance and then formatTachoIcon methods. Unfortunately this fails with an error message:

when() requires an argument which has to be 'a method call on a mock'.


推荐答案

因为您的遗留代码,您无法提出要求依赖于静态方法 getInstance()并且Mockito不允许模拟静态方法,因此以下行不起作用

What you are asking is not possible because your legacy code relies on a static method getInstance() and Mockito does not allow to mock static methods, so the following line won't work

when(FormatterService.getInstance()).thenReturn(formatter);

解决这个问题的方法有两种:

There are 2 ways around this problem:


  1. 使用允许模拟静态方法的其他模拟工具(如PowerMock)。

  1. Use a different mocking tool, such as PowerMock, that allows to mock static methods.

重构代码,这样就不必依赖静态方法了。我能想到实现这一目标的最小侵入方法是向 DriverSnapshotHandler 添加一个构造函数,它注入 FormatterService 依赖项。此构造函数将仅用于测试,您的生产代码将继续使用真正的单例实例。

Refactor your code, so that you don't rely on the static method. The least invasive way I can think of to achieve this is by adding a constructor to DriverSnapshotHandler that injects a FormatterService dependency. This constructor will be only used in tests and you production code will continue to use the real singleton instance.

public static class DriverSnapshotHandler {

    private final FormatterService formatter;

    //used in production code
    public DriverSnapshotHandler() {
        this(FormatterService.getInstance());
    }

    //used for tests
    DriverSnapshotHandler(FormatterService formatter) {
        this.formatter = formatter;
    }

    public String getImageURL() {
        return formatter.formatTachoIcon();
    }
}


然后,您的测试应该如下所示:

Then, your test should look like this :

FormatterService formatter = mock(FormatterService.class);
when(formatter.formatTachoIcon()).thenReturn("MockedURL");
DriverSnapshotHandler handler = new DriverSnapshotHandler(formatter);
handler.getImageURL();
verify(formatter, atLeastOnce()).formatTachoIcon();

这篇关于用mockito嘲笑一个单身人士的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆