单元测试广播接收器?

tho*_*att 41 junit android

这是我项目中的BroadcastReceiver,我正在寻求单元测试.当用户打电话时,它会抓取电话号码,并设置开始新活动的意图,并传入电话号码.

public class OutgoingCallReceiver extends BroadcastReceiver 
{
    @Override
    public void onReceive(Context xiContext, Intent xiIntent) 
    {
        if (xiIntent.getAction().equalsIgnoreCase(Intent.ACTION_NEW_OUTGOING_CALL))
        {
            String phoneNum = xiIntent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);

            Intent intent = new Intent(xiContext, MyActivity.class);
            intent.putExtra("phoneNum", phoneNum);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            xiContext.startActivity(intent);
            setResultData(null);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我的单元测试看起来像这样:

public class OutgoingCallReceiverTest extends AndroidTestCase
{
    private OutgoingCallReceiver mReceiver;

    @Override
    protected void setUp() throws Exception
    {
        super.setUp();

        mReceiver = new OutgoingCallReceiver();
    }

    public void testStartActivity()
    {
        Intent intent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
        intent.putExtra(Intent.EXTRA_PHONE_NUMBER, "01234567890");

        mReceiver.onReceive(getContext(), intent);        
    }
}
Run Code Online (Sandbox Code Playgroud)

这贯穿代码,但我希望我的测试能够检查意图是否已发送出去,并检查其上的电话号码.我该怎么做呢?

我还可以测试电话呼叫是否被取消(因为setResultData(null)行)?

tho*_*att 47

corlettk指出我在Android中的MockContext对象,这就是诀窍.我已经创建了它的子类TestContext,它看起来像这样:

public class TestContext extends MockContext
{
    private List<Intent> mReceivedIntents = new ArrayList<Intent>();

    @Override
    public String getPackageName()
    {
        return "com.mypackage.test";
    }

    @Override
    public void startActivity(Intent xiIntent)
    {
        mReceivedIntents.add(xiIntent);
    }

    public List<Intent> getReceivedIntents()
    {
        return mReceivedIntents;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试用例现在看起来像这样:

public class OutgoingCallReceiverTest extends AndroidTestCase
{
    private OutgoingCallReceiver mReceiver;
    private TestContext mContext;

    @Override
    protected void setUp() throws Exception
    {
        super.setUp();

        mReceiver = new OutgoingCallReceiver();
        mContext = new TestContext();
    }

    public void testStartActivity()
    {
        Intent intent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
        intent.putExtra(Intent.EXTRA_PHONE_NUMBER, "01234567890");

        mReceiver.onReceive(mContext, intent);        
        assertEquals(1, mContext.getReceivedIntents().size());
        assertNull(mReceiver.getResultData());

        Intent receivedIntent = mContext.getReceivedIntents().get(0);
        assertNull(receivedIntent.getAction());
        assertEquals("01234567890", receivedIntent.getStringExtra("phoneNum"));
        assertTrue((receivedIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0);
    }
}
Run Code Online (Sandbox Code Playgroud)


cor*_*ttk 27

马特,

听起来你需要模拟一个Context ...然后将你的方法交换到接受接口而不是具体的类:public void onReceive(IContext c, IIntent i)只是为了测试的目的.但是后面的Context和Intent类不是你的......他们是Android的...所以你不能"只是"让它们实现你的接口,所以你必须"包装"它们才能暴露你的界面,这是很多代码,而不是很多.很讨厌!!!

所以我开始怀疑以前是否有人经历过这一切,并为我们做过坚硬的工作......并且tada:http://developer.android.com/reference/android/test/mock/package-summary.html

干杯.基思.


小智 6

由于这个问题被要求嘲笑框架已经发展了很多.使用mockito,您现在不仅可以模拟接口,还可以模拟类.所以我建议通过模拟上下文并使用ArgumentCapture来解决这个问题:

import static org.mockito.Mockito.*;

public class OutgoingCallReceiverTest extends AndroidTestCase {
    private OutgoingCallReceiver mReceiver;
    private Context mContext;

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        //To make mockito work
        System.setProperty("dexmaker.dexcache", 
                mContext.getCacheDir().toString());

        mReceiver = new OutgoingCallReceiver();
        mContext = mock(Context.class);
    }

    public void testStartActivity() {
        Intent intent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
        intent.putExtra(Intent.EXTRA_PHONE_NUMBER, "01234567890");

        mReceiver.onReceive(mContext, intent);
        assertNull(mReceiver.getResultData());

        ArgumentCaptor<Intent> argument = ArgumentCaptor.forClass(Intent.class);
        verify(mContext, times(1)).startActivity(argument.capture());

        Intent receivedIntent = argument.getValue();         
        assertNull(receivedIntent.getAction());
        assertEquals("01234567890", receivedIntent.getStringExtra("phoneNum"));
        assertTrue((receivedIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0);
    }
}
Run Code Online (Sandbox Code Playgroud)