【发布时间】:2021-04-03 12:49:27
【问题描述】:
我正在为我的 Android 模块编写 Junit 测试并在 RobolectricTestRunner 的帮助下运行它。我已经模拟了一个名为authenticationChannel1 的接口AuthenticationChannnel,并希望在调用authenticationChannel1 上的方法时对一些已定义的对象执行一些操作。我正在使用 Mockito 的 Mockito.doAnswer(..).when(authenticationChannel1).<method>() 功能。
我的@Before 方法中的方法的第一个存根运行良好。当我尝试在我的一个测试用例中存根另一种方法时,我得到NullPointerException。这是我的代码:
@RunWith(RobolectricTestRunner.class)
public class AuthenticationManagerTests {
private AuthenticationManager authenticationManager;
private final Context context = RuntimeEnvironment.application;
private final WeakReference<Context> contextWeakReference = new WeakReference<>(context);
@Mock(name="channel1")
AuthenticationChannel authenticationChannel1;
Event<AuthChannelEvent> authChannel1Event;
@Mock(name="channel2")
AuthenticationChannel authenticationChannel2;
Event<AuthChannelEvent> authChannel2Event;
private CountDownLatch countDownLatch;
@Before
public void before() {
MockitoAnnotations.initMocks(this);
authChannel1Event = new Event<>();
authChannel2Event = new Event<>();
// Setting up the event handlers for the channel 1
Mockito.doAnswer(invocation -> {
authChannel1Event.addEventHandler(invocation.getArgument(0));
return null;
})
.when(authenticationChannel1) // This runs just fine ..
.subscribeToAuthenticationChannelLifecycleEvent(any());
// Setting up the event handlers for the channel 2
Mockito.doAnswer(invocation -> {
authChannel2Event.addEventHandler(invocation.getArgument(0));
return null;
})
.when(authenticationChannel2)
.subscribeToAuthenticationChannelLifecycleEvent(any());
countDownLatch = new CountDownLatch(1);
final List<AuthenticationChannel> authenticationChannels = new ArrayList<>();
authenticationChannels.add(authenticationChannel1);
authenticationChannels.add(authenticationChannel2);
authenticationManager = // Initializing the object with the implementation to test ..
// Setting up global mock methods ..
Mockito.when(authenticationChannel1.getChannelIdentifier()).thenReturn("channel1");
Mockito.when(authenticationChannel2.getChannelIdentifier()).thenReturn("channel2");
// Mocking encryption key from authentication channels ...
try {
Mockito.when(authenticationChannel1.getEncryptionKeyElseAuthenticate(any(), any()))
.thenReturn(KeyUtil.getSecureRandomBytes(CryptoConstants.KEY_SIZE_128 / 8));
} catch (AuthenticationException e) {
e.printStackTrace();
}
try {
Mockito.when(authenticationChannel2.getEncryptionKeyElseAuthenticate(any(), any()))
.thenReturn(KeyUtil.getSecureRandomBytes(CryptoConstants.KEY_SIZE_128 / 8));
} catch (AuthenticationException e) {
e.printStackTrace();
}
// Setting context to the authentication channels ..
authenticationChannel1.setTriggeringContext(context);
authenticationChannel2.setTriggeringContext(context);
}
@Test
public void test_SetupChannel1() {
final boolean[] setupSuccess = {false};
Mockito.when(authenticationChannel1
.isAuthenticationChannelUsagePossibleOnDevice()).thenReturn(true);
Mockito.when(authenticationChannel2
.isAuthenticationChannelUsagePossibleOnDevice()).thenReturn(true);
// Setting up the event for authentication manager ...
authenticationManager.subscribeToAuthenticationManagerLifecycleEvent(new Event.EventHandler<AuthManagerEvent>() {
@Override
public void run(AuthManagerEvent authManagerEvent) {
if(authManagerEvent.getEventName().equals(AUTH_MANAGER_SETUP_SUCCESS)) {
setupSuccess[0] = true;
}
countDownLatch.countDown();
}
@Override
public Executor getExecutor() {
return MoreExecutors.directExecutor();
}
});
// Intercepting the call of the setup method for the authentication channel ..
Mockito.doAnswer(invocation -> {
// Intercepting the call of calling of the authentication channel 1 and raising event
// for success ...
authChannel1Event.raiseEvent(new AuthChannelEvent(
CHANNEL_SETUP_SUCCESS,
"channel1",
new AuthPurpose(AuthenticationPurpose.
PURPOSE_SETUP,
"channel1",
false
)
));
return null;
})
.when(authenticationChannel1) // Getting NullPoinnterException here ..
.setUpAuthenticationChannel(any(), any());
..............
}
}
有人能指出我在这里可能出错的地方吗?我浏览了一个有趣的帖子:https://medium.com/kenshoos-engineering-blog/mockito-gotcha-beware-of-method-invocation-when-stubbing-65cf5cf2e4af。虽然这与我的情况非常相似,但使用了另一种 Mockito 的模拟方式。
编辑 1 添加堆栈跟踪
java.lang.NullPointerException
at in.zeta.apollo.encryptedstore.AuthenticationManagerTests.test_SetupChannel1(AuthenticationManagerTests.java:186)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:467)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:250)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:176)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:49)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:142)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Process finished with exit code 255
【问题讨论】:
-
你似乎没有实例化 authChannel1Event
-
@stultuske 我已经在之前的方法中做到了。
-
请同时发布异常的完整堆栈跟踪。
-
@TimothyTruckle 完成。
标签: java android unit-testing mockito