如何使用jmockit注入模拟的依赖项

如何使用jmockit注入模拟的依赖项

问题描述:

当前,我尝试了解@Injectable@Tested批注的工作方式.我已经做过一些测试并且理解了这个概念,但是我不知道如何在现实世界的应用程序中使用这些注释.

Currently I try to understand how the @Injectable and @Tested annotations are working. I already did some tests and understood the concept but I didn't get how I can use those annotations in real world applications.

比方说,我们正在开发一个依赖于Web服务的语言翻译器类. Web服务方法封装在单独的类中:

Let's say we are developing a language translator class which depends on a web service. The web service methods are encapsulated in a separate class:

// class to test
public class Translator() {
    private TranslatorWebService webService;

    public String translateEnglishToGerman(String word){
        webService = new TranslatorWebService();
        return webService.performTranslation(word);
    }
}

// dependency
public class TranslatorWebService {
    public String performTranslation(String word){
    // perform API calls    
    return "German Translation";
    }
}

要独立测试Translator类,我们想模拟TranslatorWebService类.根据我的理解,测试类应类似于:

To test the Translator class independently, we would like to mock the TranslatorWebService class. According to my understanding, the test class should look like:

public class TranslatorTest {
    @Tested private Translator tested;
    @Injectable private TranslatorWebService transWebServiceDependency;

    @Test public void translateEnglishToGerman() {
        new Expectations() {{
            transWebServiceDependency.performTranslation("House");
            result = "Haus";
        }};

        System.out.println(tested.translateEnglishToGerman("House"));
    }
}

当我第一次执行该测试用例时,我期望结果为"Haus".乍一看,我看到那条线

When I executed this test case for the first time, I expected the result "Haus". At second glance I saw that the line

webService = new TranslatorWebService();

将始终使用真实实例覆盖注入的模拟实例.但是,如何在不更改业务逻辑的情况下避免这种行为呢?

will always override the injected mock instance with a real instance. But how can I avoid this behavior without changing the business logic?

好问题.关于JMockit(或任何其他模拟API)对依赖关系注入的支持要注意的一点是,它仅在被测代码实际上依赖于其依赖关系注入时才使用.

Good question. The thing to notice about JMockit's (or any other mocking API) support for dependency injection is that it's meant to be used only when the code under test actually relies on the injection of its dependencies.

示例Translator依赖于注入来获得TranslatorWebService依赖关系;而是直接通过内部实例获取.

The example Translator class does not rely on injection for the TranslatorWebService dependency; instead, it obtains it directly through internal instantiation.

因此,在这种情况下,您可以简单地模拟依赖项:

So, in a situation like this you can simply mock the dependency:

public class TranslatorTest {
    @Tested Translator tested;
    @Mocked TranslatorWebService transWebServiceDependency;

    @Test public void translateEnglishToGerman() {
        new Expectations() {{
            transWebServiceDependency.performTranslation("House");
            result = "Haus";
        }};

        String translated = tested.translateEnglishToGerman("House");

        assertEquals("Haus", translated);
    }
}