У меня была такая же проблема. Тесты, которые использовали runOnUiThread () периодически терпели неудачу с NPE на полях-членах моего класса тестирования. В отладчике я мог видеть, что они были нулевыми к тому времени, когда поток пользовательского интерфейса выполнил код.
Насколько я могу судить, runOnUiThread просто отправляет событие, которое позже будет отправлено. К сожалению, это часто происходило после завершения остальной части теста в главном потоке, и мой объект был уничтожен. Это может быть связано с тем, что эмулятор слишком занят, чтобы обработать UIEvent перед продолжением теста.
Мне удалось исправить эту проблему с помощью CyclicBarrier, чтобы убедиться, что мой тест не продолжался до тех пор, пока код не был запущен в UiThread. Я создал метод для инкапсуляции этого и использовал его вместо Activity.runOnUiThread () в моих тестах:
private void myRunOnUiThread( final Runnable r) {
final CyclicBarrier barrier = new CyclicBarrier(2);
mActivity.runOnUiThread(
new Runnable() {
public void run() {
r.run();
try { barrier.await(); } catch (Exception e) { e.printStackTrace(); }
}});
try { barrier.await(); } catch (Exception e) { e.printStackTrace(); }
}
Вот как это выглядит в моем тестовом классе:
public void testFieldUI() {
myRunOnUiThread(
new Runnable() {
public void run() {
mRateView.requestFocus();
mRateView.selectAll();
}
}
);
sendKeys(KeyEvent.KEYCODE_DEL); // delete everything
assertTrue("rate is deleted", mRateView.getText().length() == 0);