web-dev-qa-db-ja.com

放送受信機のユニットテスト?

これが私のユニットからの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);
        }
    }
}

これまでのところ、私の単体テストは次のようになります。

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

これはコード全体を実行しますが、インテントが送信されたことをテストで確認し、その電話番号を確認できるようにしたいと思います。どうすればよいですか?

また、(setResultData(null)行のため)通話がキャンセルされることをテストできますか?

41
thomson_matt

マット、

コンテキストをモックアップして、具体的なクラスではなく、インターフェイスを受け入れるようにメソッドを交換する必要があるようです:public void onReceive(IContext c, IIntent i)、テストのみを目的としています。しかし、ContextクラスとIntentクラスはあなたのものではありません...それらはAndroidのものです...したがって、それらに「ただ」インターフェースを実装させることはできません。そのため、それらを「ラップ」する必要があります。あなたのインターフェースを公開する。とてもヤバイ!!!

だから私は誰かがこれまでにこれまで経験したことがあるかどうか疑問に思い始め、私たちのためにハードヤードをやりました...そしてtada: http://developer.Android.com/reference/Android/test/mock/package -summary.html

乾杯。キース。

27
corlettk

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

そして私のテストケースは次のようになります:

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);
    }
}
47
thomson_matt

この質問が尋ねられて以来、モックフレームワークはかなり進化しました。 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);
    }
}
6
Pascal Zaugg