Модульное тестирование ответа сети. Работает при отладке, а не при фактическом запуске

В настоящее время я пытаюсь проверить, действительно ли получен сетевой ответ.

Хотя я понимаю, что это не то, что я должен делать в отношении тестирования, это любопытство по моей собственной воле, и я хотел бы продолжить, если это возможно.

В нынешнем виде я успешно создал тест. Запрос отправляется в очередь залпа без проблем.

Теперь нечетная часть:

Этот запрос никогда не выполняется. Вот идея того, как я это тестирую:

 @Test
    public void testSimpleGetResponseFromServerVolley() throws Exception {
        final CountDownLatch signal = new CountDownLatch(1);

        NetworkClass.NetworkListener listener = new NetworkClass.NetworkListener() {
            @Override
            public void onResponse(Response response) {
                assertThat(response != null);
                System.out.println("Got Response");
                signal.countDown();

            }

            @Override
            public void onError(Throwable error) {
                System.out.println("No Response");
                signal.countDown();
            }
        };
        NetworkClass.getResponseFromServer(null, listener);
        signal.await();
    }

Этот код неожиданно приводит к зависанию теста и его завершению.

Однако здесь я перестаю терять понимание ситуации:

Если я запускаю тест с помощью debug и выполняю его построчно, тест выполняется успешно и приходит ответ.

Что, по моему мнению, происходит:

Когда я прохожу через отладку, залп requestQueue успешно продолжается и делает запрос, и ответ получен до вызова await().

Когда я не выполняю отладку, await() блокирует поток, который обрабатывает все это.

Любые идеи о том, как я могу справиться с этим?


person VicVu    schedule 04.05.2016    source источник
comment
@Тест? что это?   -  person zgc7009    schedule 04.05.2016
comment
Это тест jUnit, как предполагает мой тег.   -  person VicVu    schedule 04.05.2016
comment
Если утверждение терпит неудачу, countDown() никогда не вызывается. Я не знаю, как junit ведет себя в многопоточном тесте, но я видел странное поведение в этой ситуации с другими средами тестирования.   -  person 1.618    schedule 04.05.2016
comment
Нет, assert не терпит неудачу, тест просто зависает на неопределенный срок.   -  person VicVu    schedule 04.05.2016
comment
Попробуйте использовать signal.await() с тайм-аутом, а затем посмотрите, произойдет ли тайм-аут. Так вы точно будете знать, является ли это причиной зависания теста.   -  person mdewit    schedule 04.05.2016
comment
Также похоже, что у вас может быть проблема с синхронизацией потоков. Когда вы работаете в режиме отладки, у отдельных потоков будет меньше шансов конфликтовать друг с другом, потому что все делается поэтапно. При нормальной работе все происходит намного быстрее, и повышается вероятность возникновения таких проблем, как одновременный доступ и т. д. Убедитесь, что ни один из потоков не выдает какие-либо исключения, которые не регистрируются.   -  person mdewit    schedule 04.05.2016
comment
@mdewit да, по истечении тайм-аута тест завершается (без желаемого результата), поэтому зависание вызывается await (). Кроме того, я проверил все потоки, нигде нет исключений, и все потоки все еще существуют, но все ждут.   -  person VicVu    schedule 04.05.2016


Ответы (1)


Volley полагается на Looper.getMainLooper() для обработки своих исполнений. При использовании RobolectricTestRunner Robolectric имитирует это, и поэтому он не будет правильно настроен, что приведет к неудачному тесту.

В моем конкретном случае, когда я использовал точки останова, система на самом деле делает настройку основного цикла, потому что система использует его для отображения точек останова/инструментов отладки. Таким образом, это описывает причину поведения, обнаруженного в моем первоначальном вопросе.

Теперь, чтобы решить, как получить реальные сетевые ответы с помощью Volley во время модульного теста, исполнитель должен быть изменен, чтобы не использовать основной цикл.

В качестве простого решения создайте очередь запросов, которая использует Executor.singleThreadExecutor() вместо основного цикла.

Вот что я имею в виду:

    //Specific test queue that uses a singleThreadExecutor instead of the mainLooper for testing purposes.
public RequestQueue newVolleyRequestQueueForTest(final Context context) {
    File cacheDir = new File(context.getCacheDir(), "cache/volley");
    Network network = new BasicNetwork(new HurlStack());
    ResponseDelivery responseDelivery = new ExecutorDelivery(Executors.newSingleThreadExecutor());
    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network, 4, responseDelivery);
    queue.start();
    return queue;
}

Затем используйте это как очередь запросов для Volley во время тестов.

Ключ здесь:

ResponseDelivery responseDelivery = new ExecutorDelivery(Executors.newSingleThreadExecutor());

Надеюсь это поможет!

person VicVu    schedule 09.05.2016
comment
Можете ли вы немного уточнить свой ответ, чтобы он был полезен и другим? - person middlestump; 31.05.2016
comment
@middlestump да, извините, я забыл об этом ответе после того, как ответил на такой же вопрос с помощью okhttp. Обновление с кодом сейчас. - person VicVu; 31.05.2016
comment
Mockito это не нравится: new MockContext().getCacheDir() . Что я мог с этим поделать? - person Alberto M; 16.11.2017
comment
@AlbertoM, вы должны издеваться над этой функцией. Я просто делаю это: when(mockContext.getCacheDir()).thenReturn(new File("test")); - person VicVu; 17.11.2017
comment
Я пробую это решение, но оно не работает в моем случае. Я использовал эту функцию в качестве очереди запросов, но до сих пор не могу получить ответ в модульных тестах. - person rozeri dilar; 15.10.2019