Тест класса инструментального модуля - не удается создать обработчик внутри потока, который не вызвал Looper.prepare()

Извините, я посмотрел учебники повсюду и не нашел ответ, который я ищу. Сейчас я следую учебному пособию Google здесь: https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html

Я пытаюсь создать инструментальный тест, и когда я его запускаю, я получаю сообщение об ошибке: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

Итак, мой тест выглядит следующим образом:

    package testapp.silencertestapp;

import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class MainActivityTest {

    private MainActivity testMain;

    @Before
    public void createActivity(){
        testMain = new MainActivity();
    }

    @Test
    public void checkFancyStuff(){
        String time = testMain.createFancyTime(735);

        assertThat(time, is("07:35"));
    }
}

И я пытаюсь запустить метод внутри основной деятельности следующим образом (это выдержка):

public class MainActivity extends AppCompatActivity {

    private TimePicker start;
    private TimePicker end;

@Override
    protected void onCreate(Bundle savedInstanceState) {
        start = (TimePicker) findViewById(R.id.startPicker);
        end = (TimePicker) findViewById(R.id.endPicker);
}

 String createFancyTime(int combinedTime) {

        StringBuilder tempString = new StringBuilder(Integer.toString(combinedTime));
        if(tempString.length()==4){
            tempString = tempString.insert(2, ":");
        }
        else if (tempString.length()==3){
            tempString = tempString.insert(1, ":");
            tempString = tempString.insert(0, "0");
        }
        else if(tempString.length()==2){
            tempString = tempString.insert(0, "00:");
        }
        else if(tempString.length()==1){
            tempString = tempString.insert(0, "00:0");
        }
        return tempString.toString();
    }

Я предполагаю, что это проблема, потому что я не запускаю службу правильно или что-то в этом роде - я пытался использовать несколько способов, но я просто везде получаю ошибки. Поиск здесь и эта ошибка популярны, но не в связи с тестированием, поэтому интересно, может ли кто-нибудь любезно указать мне правильное направление, чтобы я мог проверить методы в этом классе?

2 ответа

Решение

Ошибка происходит потому, что Looper неправильно настроена для тестируемой системы (MainActivity).

В то время как Activity, Fragment и т.д. имеют конструкторы без аргументов, они предназначены для создания экземпляров ОС Android и, как таковые, вызывают MainActivity = new Activity() недостаточно, чтобы получить полностью работающий экземпляр звезды смерти в комплекте с Handler а также Looper,

Есть два варианта, если вы хотите продолжить тестирование:

  1. Если вы хотите проверить реальный экземпляр Activity, это должен быть инструментальный тестовый модуль (androidTest не test) и @TestRule заставит ОС Android правильно создать экземпляр Activity:

    @Rule
    public ActivityTestRule<MainActivity> mActivityRule =
        new ActivityTestRule(MainActivity.class);
    
  2. Если вы предпочитаете продолжать писать локальные модульные тесты, которые запускаются в IDE, вы можете использовать http://robolectric.org/. Robolectric будет корректно корректировать поведение теневой активности, чтобы вы могли тестировать компоненты, которые полагаются на Looper и т. д. Обратите внимание, что здесь есть некоторые настройки.

Вот как я это решил. Я запустил тестовый пример в основном потоке, используя runOnMainSync. Вот полное решение:

      @RunWith(AndroidJUnit4::class)
class AwesomeViewModelTest {

    @Test
    fun testHandler() {

        getInstrumentation().runOnMainSync(Runnable {
            val context = InstrumentationRegistry.getInstrumentation().targetContext

          // Here you can call methods which have Handler

       
        })
    }


}
Другие вопросы по тегам