簡體   English   中英

如何使用Robolectric測試IntentService?

[英]How to test an IntentService with Robolectric?

我想測試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不為null,但似乎沒有調用onHandleIntent()

我該怎么測試呢?

Robolectric有一個ServiceController ,可以像活動一樣通過服務生命周期。 該控制器提供執行相應服務回調的所有方法(例如controller.attach().create().startCommand(0, 0).destroy() )。

從理論上講,我們可以預期IntentService.onStartCommand()將通過其內部Handler觸發IntentService.onHandleIntent(Intent) 但是這個Handler使用一個在后台線程上運行的Looper ,我不知道如何讓這個線程前進到下一個任務。 解決方法是創建模仿相同行為的TestService ,但在主線程(用於運行測試的線程onHandleIntent(Intent)上觸發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);
        }
    }
}

更新 :或者,為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());
}

然后我運行測試,一切都很好

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);

注意:即使您正在測試IntentService,也要使用Robolectric.buildService (而不是.buildIntentService )。 據我所知, .buildIntentService目前無法正常工作。

更新2017-05-17:

buildIntentService問題buildIntentService修復

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM