如何在Android JUnit测试中测试来自服务的Handler回调?

时间:2014-05-02 15:27:06

标签: java android unit-testing junit handler

我想测试以下(标准?)方案

  • 活动使用Service对象来执行某些操作。
  • 服务使用bindService(..)绑定到活动。
  • 服务本身允许通过Binder访问,它在onBind()中返回,提供对服务对象本身的访问(所有内容都发生在同一个线程上)。
  • 在onServiceConnected(..)中,活动通过Binder访问服务,并将Service a Handler对象发送给活动。
  • 所以沟通是: 活动 - >通过直接呼叫服务进行服务。和服务 - >通过Handler对象从Activity注入服务的活动

此方案运行正常。 App中没有问题。

但是现在我也想写自动单元测试,我遇到了问题,处理程序似乎不再发送和处理消息。

我写了像这样的Android JUnit测试

public class EpcServiceMockTest extends ServiceTestCase<EpcServiceMock> {...}

使用这样的测试方法

public void testConnectToDevice() {
    Intent serviceIntent = new Intent(getContext(), EpcServiceMock.class);
    IBinder binder = bindService(serviceIntent);
    EpcServiceHandlerMock mockHandler = new EpcServiceHandlerMock(this);
    EpcServiceMock service = (EpcServiceMock) ((EpcServiceBase.LocalBinder) binder).getService(mockHandler);
service.doSomething(..);

此设置正常。该服务运行并执行被调用的方法。但每次使用处理程序发送消息时,都不会执行消息。即,永远不会在Handler上调用handleMessage()。

    Message callbackMsg = mCallbackHandler.obtainMessage(CB_CONNECT_TO_NULL_DEVICE, mDevice);
    mCallbackHandler.sendMessage(callbackMsg);

调用此代码。 Handler mCallbackHandler是正确的类型。没有错误。什么都没发生。在Handler中没有调用handleMessage()。

首先我认为存在竞争条件,因为Looper在另一个线程上。所以我让测试用例睡了一会儿:

(..)
service.doSomething(..);
Thread.sleep(3000);
Log.d(TAG, "Waking up ...");
callbacks = mockHandler.receivedCallbacks;
assertEquals("one callback", 1, callbacks.size());

但仍然没有。在测试场景中永远不会调用处理程序中的handleMessage()方法。但它在真正的App中运行良好。

在Android JUnit测试中测试处理程序是否存在根本问题?

2 个答案:

答案 0 :(得分:0)

问题解决了:

我是如此愚蠢,以至于不在一个单独的线程上启动Handler。因此Handler运行在与JUnit Test相同的线程上。因此,JUnit首先完成,看不到Handler的结果而失败。

当我将Handler放在不同的线程上时,一切都在JUnit测试中正常工作。

答案 1 :(得分:0)

或者,您可以模拟同步处理程序而不是Thread.sleep

Mockito.when(testHandler.post(any(Runnable.class))).thenAnswer(new Answer<Object>() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            ((Runnable) invocation.getArgument(0)).run();
            return null;
        }
    });