Mockito:与该模拟游戏的互动为零

时间:2019-06-25 08:44:03

标签: java junit mockito

我有一个要测试的课程。

@Configuration
@Import(EmailageConfiguration.class)
public class EmailageServiceConfiguration {

    private static final String EMAILAGE_ACCOUNT_ID_CONFIG_KEY = "emailage.key";
    private static final String EMAILAGE_API_KEY_CONFIG_KEY = "emailage.secret";

    @Bean
    public EmailageConfigHolder emailageConfigHolder(Environment env) {

        final EmailageConfigHolder holder = new EmailageConfigHolder();

        holder.setApiKey(env.getRequiredProperty(EMAILAGE_API_KEY_CONFIG_KEY));
        holder.setAccountId(env.getRequiredProperty(EMAILAGE_ACCOUNT_ID_CONFIG_KEY));

        return holder;
    }

}

提供了我的测试课程,

@RunWith(MockitoJUnitRunner.class)
public class EmailageServiceConfigurationTest {

    @InjectMocks
    private EmailageServiceConfiguration configuration;

    @Mock
    private Environment environment;

    @Mock
    private EmailageConfigHolder holder;

    @Test
    public void testEmailageConfigHolder() {

        when(environment.getRequiredProperty(anyString())).thenReturn(anyString());

        configuration.emailageConfigHolder(environment);

        verify(holder, times(1)).setApiKey(anyString());
        verify(holder, times(1)).setAccountId(anyString());
    }
}

我得到下面提供的错误堆栈,

  

想要但不被调用:   holder.setApiKey();   -> com.ratepay.ella.service.config.EmailageServiceConfigurationTest.testEmailageConfigHolder(EmailageServiceConfigurationTest.java:48)   实际上,与该模拟游戏的互动为零。   想要但不被调用:   holder.setApiKey();   -> com.ratepay.ella.service.config.EmailageServiceConfigurationTest.testEmailageConfigHolder(EmailageServiceConfigurationTest.java:48)   实际上,与该模拟游戏的互动为零。     在com.ratepay.ella.service.config.EmailageServiceConfigurationTest.testEmailageConfigHolder(EmailageServiceConfigurationTest.java:48)       在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处       在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)       在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)       在java.lang.reflect.Method.invoke(Method.java:498)       在org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:50)       在org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)       在org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)       在org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)       在org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)       在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)       在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)       在org.junit.runners.ParentRunner $ 3.run(ParentRunner.java:290)       在org.junit.runners.ParentRunner $ 1.schedule(ParentRunner.java:71)       在org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)       在org.junit.runners.ParentRunner.access $ 000(ParentRunner.java:58)       在org.junit.runners.ParentRunner上$ 2.evaluate(ParentRunner.java:268)       在org.junit.runners.ParentRunner.run(ParentRunner.java:363)       在org.mockito.internal.runners.DefaultInternalRunner $ 1.run(DefaultInternalRunner.java:79)       在org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)       在org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)       在org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)       在org.junit.runner.JUnitCore.run(JUnitCore.java:137)       在com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)       在com.intellij.rt.execution.junit.IdeaTestRunner $ Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)       在com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)       在com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

我该如何更正测试?

2 个答案:

答案 0 :(得分:5)

这里:

final EmailageConfigHolder holder = new EmailageConfigHolder();

Mockito无法将模拟注入到 local 变量中。 documentation确实很清楚:

  

Mockito将尝试按顺序并仅按如下所述通过构造函数注入,setter注入或属性注入来注入模拟。

基本上,通过在方法正文中使用new(),您编写了难以测试的代码。因为使用Mockito,您具有个选项来控制new()将在该方法主体中返回的内容。

解决之道:

  • 将“持有人”设置为您类的一个字段,然后通过该注释或通过接受持有人实例的构造函数进行注入
  • 将实例作为参数传递给方法

或者假设您可以在单元测试设置中的生产代码中实际创建一个新的Holder对象,并且在您返回该对象时,只需声明返回对象的属性。从这个角度来看,您根本不需要在这里使用模拟。只需验证从该调用返回的对象是否具有预期的属性即可!

或者,(不推荐)您可以使用PowerMock(ito)或JMockit,以获得对new()的调用的控制权。但是如前所述:更好地重新编写代码,使其易于测试。

顺便说一句:真正的答案是您退后一步,阅读有关Mockito的不错的教程。您无法通过反复试验来学习如何使用这样的框架。通过漂亮的小示例学习如何正确地做到这一点,然后,当您了解如何连接点之后,将其应用于您自己的代码!

答案 1 :(得分:0)

虽然其他答案更适合这种情况,但我无法更新代码,最后编写了此测试代码。

@RunWith( MockitoJUnitRunner.class )
public class EmailageServiceConfigurationTest {

    private static final String ACCOUNT_ID = "emailage.key";
    private static final String API_KEY = "emailage.secret";

    @InjectMocks
    private EmailageServiceConfiguration configuration;

    @Mock
    private Environment environment;

    @Test
    public void testEmailageConfigHolder() {

        configuration.emailageConfigHolder( environment );

        verify( environment, times( 1 ) ).getRequiredProperty( API_KEY );
        verify( environment, times( 1 ) ).getRequiredProperty( ACCOUNT_ID );
    }
}