我正在尝试为我的Android应用程序编写一个单元测试,但无法用mockito做我想做的事情。这与Robolectric一起使用,我工作得很好并证明单元测试工作正常。
我想测试按钮是否会打开新活动,具体取决于是否连接了蓝牙设备。显然,在我的测试中没有与蓝牙连接的设备,但我想假装好像有。蓝牙连接的状态存储在我的Application类中。没有可公开访问的方法来更改此值。
所以基本上应用程序中的逻辑是这样的:
HomeActivity.java:
//this gets called when the button to open the list is clicked.
public void openListActivity(View button) {
MyApplication myApplication = (MyApplication) getApplication();
if (myApplication.isDeviceConnected() {
startActivity(new intent(this, ListActivity.class));
}
}
为了测试这个,我做了以下事情:
TestHomeActivity.java:
@Test
public void buttonShouldOpenListIfConnected() {
FlexApplication mockedApp = Mockito.mock(MyApplication.class);
Mockito.when(mockedApp.isDeviceConnected()).thenReturn(true);
//listViewButton was setup in @Before
listViewButton.performClick();
ShadowActivity shadowActivity = Robolectric.shadowOf(activity);
Intent intent = shadowActivity.getNextStartedActivity();
assertNotNull(intent); //this fails because no new activity was opened. I debugged this and found that isDeviceConnected returned false.
ShadowIntent shadowIntent = Robolectric.shadowOf(intent);
assertThat(shadowIntent.getComponent().getClassName(), equalTo(ListActivity.class.getName()));
}
所以我的单元测试失败了,因为isDeviceConnected的调用(在活动中)返回false,即使我想到我告诉它使用模拟框架返回true。我希望我的测试让这个方法返回true。这不是mockito所做的,还是我完全错误的如何使用mockito?
答案 0 :(得分:5)
这就是mockito的工作原理,但问题是:listViewButton
是否正在使用mockedApp
?似乎没有,因为您在测试方法中创建mockedApp
并且从未在任何地方设置它。 Mockito不会模拟Application
的所有实例的方法调用,只会从你声明为模拟的内容开始。
我个人不知道android如何与Application
类一起使用,但你必须将它设置在某个地方,以便listView使用你的mockedApp
而不是正常接收的内容。
修改强>
更新后的问题后,您可以使用受保护的方法转换getApplication
,spy
改变listViewButton
mockedApp
并使其返回listViewButton
。这有点不好,但如果你不能将你的应用程序模拟对象设置为public HomeActivity {
...
protected MyApplication getApplication() {
// real code
}
...
}
public void TestHomeActivity {
private HomeActivity homeActivity;
@Before
public void setUp() {
this.homeActivity = spy(new HomeActivity());
}
@Test
public void buttonShouldOpenListIfConnected() {
// given
FlexApplication mockedApp = Mockito.mock(MyApplication.class);
Mockito.when(mockedApp.isDeviceConnected()).thenReturn(true);
// IMPORTANT PART
given(homeActivity.getApplication()).willReturn(mockedApp);
...
}
}
,那就是一种方法。
<强> EDIT2 强>
使用BDDMockito
在您的测试中使用间谍以提高可读性的示例:)
spy
之后,您的测试应该按预期工作。但我强调:只有在无法将mockedApp
注入HomeActivity时才使用{{1}}。
答案 1 :(得分:2)
您的模拟版本未被调用。
看到那个电话,getApplication()
? (下面)。那将返回MyApplication类的真实副本,而不是您的模拟版本。您需要拦截getApplication()
调用并传入模拟的Application对象。
HomeActivity.java:
//this gets called when the button to open the list is clicked.
public void openListActivity(View button) {
MyApplication myApplication = (MyApplication) getApplication(); // returns the real thing
if (myApplication.isDeviceConnected() {
startActivity(new intent(this, ListActivity.class));
}
}
我不确定Mockito可以做到这一点。您是否尝试过自定义ShadowActivity#getApplication()方法?