我有一个我想测试的类。
@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.emailageserageserviceconfigurationTest.testemailageconfigholder(emagageserviceconfigurationtest.java:48( 实际上,与此模拟的相互作用为零。 想要但没有被调用: holder.setapikey((; ->在com.ratepay.ella.service.config.emailageserageserviceconfigurationTest.testemailageconfigholder(emagageserviceconfigurationtest.java:48( 实际上,与此模拟的相互作用为零。 在com.ratepay.ella.service.config.emailageserviceconfigurationtest.testemailageconfigholder(emagageserviceconfigurationtest.java:48( 在sun.reflect.nativemethodaccessorimpl.invoke0(天然方法( 在sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:62( 在sun.reflect.delegatingmethodaccessorimpl.invoke(授权methodaccessorimpl.java:43( 在java.lang.reflect.method.invoke(method.java:498( atorg.junit.runners.model.frameworkmethod $ 1.RunreFlectiveCall(frameworkmethod.java:50( at org.junit.internal.runners.model.reflectivecallable.run(ReflectiveCallable.java:12( atorg.junit.runners.model.frameworkmethod.invokeexplosively(frameworkmethod.java:47( atorg.junit.internal.runners.statement.invokemethod.evaluate(InvokeMethod.java:17( atorg.junit.runners.parentrunner.runleaf(parentrunner.java:325( atorg.junit.runners.blockjunit4classrunner.runchild(blockJunit4Classrunner.java:78( atorg.junit.runners.blockjunit4classrunner.runchild(blockJunit4Classrunner.java:57( atorg.junit.runners.parentrunner $ 3.run(parentrunner.java:290( at org.junit.runners.parentrunner $ 1.Schedule(pardrunner.java:71( 请访问org.junit.runners.parentrunner.runchildren(parentrunner.java:288( 请访问org.junit.runners.parentrunner.Access $ 000(parentrunner.java:58( atorg.junit.runners.parentrunner $ 2.Evaluate(pardrunner.java:268( at org.junit.runners.parentrunner.run(pardrunner.java:363( atorg.mockito.internal.runners.defaultinternalrunner $ 1.run(DefaultInternalRunner.java:79( atorg.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( atorg.junit.runner.junitcore.run(junitcore.java:137( 在com.intellij.junit4.junit4ideTestrunner.startrunnerwithargs(junit4ideTeStrunner.java:68( 在com.intellij.rt.execution.junit.ideatestrunner $ repeater.startrunnerwithargs(IdeateTertunner.java:47( 在com.intellij.rt.execution.junit.junitstarter.preparestreamsandstart(junitstarter.java:242( 在com.intellij.rt.execution.junit.junitstarter.main(junitstarter.java:70(
如何纠正测试?
在这里:
final EmailageConfigHolder holder = new EmailageConfigHolder();
Mockito无法将模拟注入 local 变量。该文档真的很清楚:
Mockito将尝试按顺序和如下所述,仅通过构造仪注入,设置器注入或财产注入来注入模拟。
基本上,通过在方法的正文中使用new()
,您编写的很难测试代码。因为使用Mockito,您有零控制new()
将在该方法主体中返回的选项。
出路:
- 使该"持有人"一个班级的字段,然后通过该注释注入,或者通过接受持有人实例的构造函数
- 将实例作为参数传递给方法
或假设您实际上可以在单元测试设置中的生产代码中创建一个新的持有器对象,并且当您是返回时,只需 servert 返回对象的属性。从这个角度来看,您根本不需要在这里使用模拟。只需验证从该调用回来的对象是否具有预期的属性!
或(不建议(,您可以转向PowerMock(ITO(或JMOCKIT,以便对new()
的呼叫进行控制。但是如所说:最好将代码重新设计为易于测试。
顺便说一句:真正的答案是,您退后一步,阅读了有关Mockito的好教程。您无法通过反复试验学习如何使用这种框架。通过不错的示例了解如何正确执行此操作,然后,当您了解如何连接点时,然后将其应用于您自己的代码!
虽然另一个答案更好地适合这种情况,但我无法更新代码,最后,编写了此测试代码。
@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 );
}
}