Подтвердить что ты не робот

Единичное тестирование вещательного приемника?

Здесь BroadcastReceiver из моего проекта, который я ищу unit test. Когда пользователь делает телефонный звонок, он захватывает номер телефона и устанавливает намерение начать новое действие, передавая номер телефона.

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

До сих пор мой unit test выглядит следующим образом:

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

4b9b3361

Ответ 1

Матовый,

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

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

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

Ответ 2

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

Ответ 3

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