Я хочу протестировать внутри unit test, был ли запущен сигнал тревоги, запрограммированный с помощью AlarmManager
, и если да, то если он запущен в течение правильного периода.
Здесь тестируется класс приемника. Я создал его в своем тестовом проекте. (ПРИМЕЧАНИЕ: он не зарегистрирован в манифесте)
public class MockBroadcastReceiver extends BroadcastReceiver {
private static int numTimesCalled = 0;
MockBroadcastReceiver(){
numTimesCalled = 0;
}
@Override
public void onReceive(Context context, Intent intent) {
numTimesCalled++;
}
public static int getNumTimesCalled() {
return numTimesCalled;
}
public static void setNumTimesCalled(int numTimesCalled) {
MockBroadcastReceiver.numTimesCalled = numTimesCalled;
}
}
И вот unit test. Метод programReceiver
фактически принадлежит классу в основном проекте, но я включил его внутри теста, так что вам не нужно читать столько кода.
public class ATest extends AndroidTestCase {
MockBroadcastReceiver mockReceiver;
@Override
protected void setUp() throws Exception {
mockReceiver = new MockBroadcastReceiver();
getContext().registerReceiver(mockReceiver, new IntentFilter());
}
@Override
protected void tearDown() {
getContext().unregisterReceiver(mockReceiver);
mockReceiver = null;
}
public void test(){
//We're going to program twice and check that only the last
//programmed alarm should remain active.
final Object flag = new Object();
MockBroadcastReceiver.setNumTimesCalled(0);
new Thread (){
@Override
public void run(){
programReceiver(getContext(), MockBroadcastReceiver.class, 60000, 60000);
SystemClock.sleep(20000);
programReceiver(getContext(), MockBroadcastReceiver.class, 60000, 60000);
SystemClock.sleep(90000);
synchronized(flag){
flag.notifyAll();
}
}
}.start();
synchronized(flag){
try {
flag.wait();
} catch (InterruptedException e) {
}
}
assertEquals(1, MockBroadcastReceiver.getNumTimesCalled()); //should have been called at least once, but its 0.
}
private static void programReceiver(Context context, Class<? extends BroadcastReceiver> receiverClass, long initialDelay, long period){
Intent intent = new Intent(context, receiverClass);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent); //Cancel any previous alarm
alarmManager.setInexactRepeating (
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + initialDelay,
period,
pendingIntent
);
}
}
Когда я выполняю метод test
, приемник должен быть динамически зарегистрирован в setUp
. Затем я программирую один и тот же сигнал тревоги дважды. Мое намерение состояло в том, чтобы проверить, что только последний сигнал остался активным, но мне не удается вообще вызвать приемник. Тест завершается неудачно, поскольку ожидается, что он будет вызываться один раз (или, по крайней мере, несколько раз >= 1), но счетчик в макетном приемнике равен 0. Я установил точку останова в методе onReceive
, и это никогда не ударил. Я также добавил регистрацию и ничего не отображается в logcat. Поэтому я на 100% уверен, что приемник не вызван. Я также пытался увеличить время сна в потоке, потому что setInexactRepeating
срабатывает очень неточно, но я могу ждать веков, и он все еще не вызван.
Я также попытался зарегистрировать его в манифесте тестового проекта, а не программно, и результаты совпадают.
Почему приемник не вызывается?
UPDATE
Я могу подтвердить AlarmManager
не проблема. Тревоги правильно зарегистрированы в соответствии с аварийным сигналом adb dumpsys.
Теперь я пытаюсь запустить приемник, вызвав sendBroadcast
, но я в тупике. Приемник просто не будет вызван. Я попробовал контекст основного приложения, контекст тестового случая, даже ActivityInstrumentationTestCase2
. Пробовал также добавлять WakeLocks и ничего. Просто нет способа заставить его позвонить. Я думаю, что это может быть вызвано некоторыми флагами в намеренном или намеренном фильтре (андроид, по-видимому, очень разборчив с флагами).