Я пытаюсь проверить мой сетевой модуль. Когда я запускаю это на симуляторе или устройстве, обработчик в порядке, но когда я пытаюсь сделать это из тестов, handler = null и callback не вызывается. Как я могу решить эту проблему?

public void performCall(Call callToPerform){
    callToPerform.call.enqueue(new okhttp3.Callback() {
        Handler handler = new Handler();

        @Override
        public void onFailure(okhttp3.Call call, IOException e) {
            handler.post(() -> {
                for (Callback callback : callToPerform.callbacks) {
                    callback.onFailure(callToPerform, e);
                }
            });
        }

        @Override
        public void onResponse(okhttp3.Call call, final okhttp3.Response response){
            handler.post(() -> {
                for (Callback callback : callToPerform.callbacks) {
                    try {
                        callback.onResponse(callToPerform, new Response(response.body().bytes(), response.headers().toMultimap()));
                    } catch (IOException e) {
                        callback.onFailure(call, e);
                    }
                }
            });
        }
    });
}

Мой файл приложения Gradle содержит эти параметры.

testOptions {
    unitTests.returnDefaultValues = true
}
2
npmrtsv 25 Апр 2017 в 00:08

2 ответа

Лучший ответ

Хорошо, после нескольких часов исследований я нашел решение, и оно похоже на это:

package com.dpmedeiros.androidtestsupportlibrary;

import android.os.Handler;
import android.os.Looper;

import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static org.mockito.Mockito.*;

/**
 * Utility methods that unit tests can use to do common android library mocking that might be needed.
 */
public class AndroidMockUtil {

    private AndroidMockUtil() {}
    /**
     * Mocks main thread handler post() and postDelayed() for use in Android unit tests
     *
     * To use this:
     * <ol>
     *     <li>Call this method in an {@literal @}Before method of your test.</li>
     *     <li>Place Looper.class in the {@literal @}PrepareForTest annotation before your test class.</li>
     *     <li>any class under test that needs to call {@code new Handler(Looper.getMainLooper())} should be placed
     *     in the {@literal @}PrepareForTest annotation as well.</li>
     * </ol>
     *
     * @throws Exception
     */
    public static void mockMainThreadHandler() throws Exception {
        PowerMockito.mockStatic(Looper.class);
        Looper mockMainThreadLooper = mock(Looper.class);
        when(Looper.getMainLooper()).thenReturn(mockMainThreadLooper);
        Handler mockMainThreadHandler = mock(Handler.class);
        Answer<Boolean> handlerPostAnswer = new Answer<Boolean>() {
            @Override
            public Boolean answer(InvocationOnMock invocation) throws Throwable {
                Runnable runnable = invocation.getArgumentAt(0, Runnable.class);
                Long delay = 0L;
                if (invocation.getArguments().length > 1) {
                    delay = invocation.getArgumentAt(1, Long.class);
                }
                if (runnable != null) {
                    mainThread.schedule(runnable, delay, TimeUnit.MILLISECONDS);
                }
                return true;
            }
        };
        doAnswer(handlerPostAnswer).when(mockMainThreadHandler).post(any(Runnable.class));
        doAnswer(handlerPostAnswer).when(mockMainThreadHandler).postDelayed(any(Runnable.class), anyLong());
        PowerMockito.whenNew(Handler.class).withArguments(mockMainThreadLooper).thenReturn(mockMainThreadHandler);
    }

    private final static ScheduledExecutorService mainThread = Executors.newSingleThreadScheduledExecutor();

}
2
Nasreddine 22 Май 2017 в 14:44

Если вы запустите этот пример кода на JUnit, это не будет работать, потому что тесты JUnit выполняются на JVM, а инструментальные тесты выполняются на симуляторе или реальном устройстве.

Вы можете взглянуть на эту ссылку, она объясняет почему:

Инструментальные тесты или локальные тесты

1
Maxime Liege 25 Апр 2017 в 09:04
43597745