我有一个要测试的课程。
@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)
我该如何更正测试?
答案 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 );
}
}