我想测试onHandleIntent()
的方法IntentService
使用Robolectric
。
我开始与服务:
Activity activity = new Activity();
Intent intent = new Intent(activity, MyService.class);
activity.startService(intent);
ShadowActivity shadowActivity = Robolectric.shadowOf(activity);
Intent startedIntent = shadowActivity.getNextStartedService();
assertNotNull(startedIntent);
好像startedIntent
不为空,但onHandleIntent()
似乎并没有被调用。
我应该怎么测试呢?
Robolectric有ServiceController
,可以去通服务生命周期就像活动。 此控制器提供的所有方法来执行相应的服务的回调(例如controller.attach().create().startCommand(0, 0).destroy()
从理论上讲,我们可以预期, IntentService.onStartCommand()
将触发IntentService.onHandleIntent(Intent)
,通过其内部Handler
。 然而这个Handler
使用一个Looper
运行于后台线程,我不知道如何使这个线程进入下一个任务。 一种解决方法是创建TestService
模仿相同的行为,但触发onHandleIntent(Intent)
在主线程(用于运行测试线程)。
@RunWith(RobolectricGradleTestRunner.class)
public class MyIntentServiceTest {
private TestService service;
private ServiceController<TestService> controller;
@Before
public void setUp() {
controller = Robolectric.buildService(TestService.class);
service = controller.attach().create().get();
}
@Test
public void testWithIntent() {
Intent intent = new Intent(RuntimeEnvironment.application, TestService.class);
// add extras to intent
controller.withIntent(intent).startCommand(0, 0);
// assert here
}
@After
public void tearDown() {
controller.destroy();
}
public static class TestService extends MyIntentService {
public boolean enabled = true;
@Override
public void onStart(Intent intent, int startId) {
// same logic as in internal ServiceHandler.handleMessage()
// but runs on same thread as Service
onHandleIntent(intent);
stopSelf(startId);
}
}
}
UPDATE:或者,这是相当简单的创建IntentService类似的控制器,如下所示:
public class IntentServiceController<T extends IntentService> extends ServiceController<T> {
public static <T extends IntentService> IntentServiceController<T> buildIntentService(Class<T> serviceClass) {
try {
return new IntentServiceController<>(Robolectric.getShadowsAdapter(), serviceClass);
} catch (IllegalAccessException | InstantiationException e) {
throw new RuntimeException(e);
}
}
private IntentServiceController(ShadowsAdapter shadowsAdapter, Class<T> serviceClass) throws IllegalAccessException, InstantiationException {
super(shadowsAdapter, serviceClass);
}
@Override
public IntentServiceController<T> withIntent(Intent intent) {
super.withIntent(intent);
return this;
}
@Override
public IntentServiceController<T> attach() {
super.attach();
return this;
}
@Override
public IntentServiceController<T> bind() {
super.bind();
return this;
}
@Override
public IntentServiceController<T> create() {
super.create();
return this;
}
@Override
public IntentServiceController<T> destroy() {
super.destroy();
return this;
}
@Override
public IntentServiceController<T> rebind() {
super.rebind();
return this;
}
@Override
public IntentServiceController<T> startCommand(int flags, int startId) {
super.startCommand(flags, startId);
return this;
}
@Override
public IntentServiceController<T> unbind() {
super.unbind();
return this;
}
public IntentServiceController<T> handleIntent() {
invokeWhilePaused("onHandleIntent", getIntent());
return this;
}
}
onHandleIntent
是受保护的方法,所以它不能被直接调用。
我的解决办法是延长服务类在我的测试情况下,覆盖onHandleIntent
使其成为公众和调用super.onHandleIntent(intent)
然后调用onHandleIntent
直接从测试用例。
我想你已经接近这个错误的方式。 您正在测试在这里:
Intent startedIntent = shadowActivity.getNextStartedService();
assertNotNull(startedIntent);
该startService()
被调用。
然后,您必须假定Android已经正确和调用后执行他们的最终startService()
的服务将真正启动。
我认为,如果你想测试的行为onHandleIntent()
您必须只需直接调用它?
我不知道到底......但我想你要编写测试也只是测试Android框架。 你应该写两个测试。
1)测试该startService()
被调用(如你在你的例子有)。
2)测试的行为onHandleIntent()
通过直接调用它)。
我有很少的经验Robolectric
但希望这是有帮助的。
干杯
我用这个
@Before
public void setup(){
mainActivity = Robolectric.buildActivity(MainActivity.class)
.create()
.start()
.resume()
.get();
context = Robolectric.getShadowApplication().getApplicationContext();
bt_start = (Button) mainActivity.findViewById(R.id.button);
bt_stop = (Button) mainActivity.findViewById(R.id.button2);
}
@Test
public void serviceIsOn(){
bt_start.performClick();
Intent intent = Robolectric.shadowOf(mainActivity).peekNextStartedService();
assertEquals(MiService.class.getCanonicalName(),intent.getComponent().getClassName());
}
然后运行测试,一切都OK
Robolectric 3.1+
创建服务的实例
直接调用onHandleIntent
YourService svc = Robolectric.buildService(YourService.class).get();
Intent fakeIntent = new Intent();
fakeIntent.putExtra(YourService.SOME_EXTRA, "debug|fail");
svc.onHandleIntent(fakeIntent);
assertThat(something.happened).isEqualTo(true);
注意:使用Robolectric.buildService
(不.buildIntentService
),即使你正在测试一个IntentService。 .buildIntentService
目前没有工作,据我可以告诉。
更新2017年5月17日:
问题与buildIntentService
将固定在未来