Модульное тестирование вещательного приемника? - PullRequest
40 голосов
/ 24 апреля 2011

Вот 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))?

Ответы [ 3 ]

47 голосов
/ 24 апреля 2011

corlettk указал мне на объект MockContext в Android, который делает свое дело. Я сделал его подкласс, 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);
    }
}
27 голосов
/ 24 апреля 2011

Matt,

Звучит так, будто вам нужно смоделировать контекст ... и затем переключить ваши методы на прием интерфейсов вместо конкретных классов: public void onReceive(IContext c, IIntent i), просто для целей тестирования.Но тогда классы Context и Intent - это не ваши, а ... они Android ... поэтому вы не можете "просто" заставить их реализовать ваши интерфейсы, поэтому вам придется "обернуть" их, чтобывыставить ваш интерфейс, который довольно много кода для небольшого выигрыша.Очень отвратительно !!!

Так что я начал задаваться вопросом, прошел ли кто-то через все это раньше, и сделал ли нам трудные задания ... и тада: http://developer.android.com/reference/android/test/mock/package-summary.html

ПриветствияКит.

6 голосов
/ 14 ноября 2013

С тех пор, как этот вопрос был задан, насмешливые рамки развивались в значительной степени. С 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...