Android Unit Test с дооснащением и Mockito
Я выделил методы api для переопределения api из кода активности, и я хочу сделать unit test для этих методов, например:
Интерфейс:
public interface LoginService {
@GET("/auth")
public void basicLogin(Callback<AuthObject> response);
}
и это метод, который выполняет вызов, в основном я получаю объект по шине событий.
public class AuthAPI {
private Bus bus;
LoginService loginService;
public AuthAPI(String username, String password) {
this.bus = BusProvider.getInstance().getBus();
loginService = ServiceGenerator.createService(LoginService.class,
CommonUtils.BASE_URL,
username,
password);
}
public void Login() {
loginService.basicLogin(new Callback<AuthObject>() {
@Override
public void success(AuthObject authObject, Response response) {
bus.post(authObject);
}
@Override
public void failure(RetrofitError error) {
AuthObject authObject = new AuthObject();
authObject.setError(true);
bus.post(authObject);
}
});
}
}
И вот тест
@RunWith(MockitoJUnitRunner.class)
public class AuthCallTest extends TestCase {
AuthAPI authAPI;
@Mock
private LoginService mockApi;
@Captor
private ArgumentCaptor<Callback<AuthObject>> cb;
@Before
public void setUp() throws Exception {
authAPI = new AuthAPI("username", "password");
MockitoAnnotations.initMocks(this);
}
@Test
public void testLogin() throws Exception {
Mockito.verify(mockApi).basicLogin((cb.capture()));
AuthObject authObject = new AuthObject();
cb.getValue().success(authObject, null);
assertEquals(authObject.isError(), false);
}
}
когда я запускаю тест, у меня есть эта ошибка
Wanted but not invoked:
mockApi.basicLogin(<Capturing argument>);
-> at AuthCallTest.testLogin(AuthCallTest.java:42)
Actually, there were zero interactions with this mock.
Что я сделал не так, это сводит меня с ума
Я старался следовать этому руководству без успеха:
http://www.mdswanson.com/blog/2013/12/16/reliable-android-http-testing-with-retrofit-and-mockito.html
кто-то мне помогает: (
Ответы
Ответ 1
Статья не очень понятна, так как она пропускает шаги настройки. Посетив проект GitHub, указанный в статье, вы можете увидеть полный исходный код, который объясняет эти недостающие шаги:
1) Образцы кода извлекаются из тестового класса, проверяющего конкретную активность. Как часть настройки (т.е. В @Before
), она заменяет ссылку Activity на реализацию API GitHub макетной. Затем он вызывает Activity onCreate()
.
2) Во время onCreate()
, активность вызывает вызов заменяемого теперь GitHub API, передавая его Callback
объект.
Эти первые два шага объясняют, почему работает шаг Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture());
в начале каждого теста. Когда тест выполняется после @Before
, mockApi действительно вызвал свой метод repositories()
.
Остальная часть кода легче понять после этого. Поскольку он создал только mockApi
, но не изменил фактический Callback
, содержимое активности изменилось. Остальная часть кода затем проверяет, что эти изменения произошли, либо путем проверки ListView или Toasts.
Чтобы ответить на ваш вопрос, вам необходимо:
1) В начале вашего тестового метода замените объект AuthAPI loginService объектом mockApi, затем вызовите AuthAPI.Login()
.
2) Используйте verify()
, поскольку вы уже должны проверить, что функция была вызвана.
3) Создайте образец AuthObject
и передайте его функции cb.getValue().success()
.
4) Получите AuthObject
из своего Bus
и убедитесь, что он тот же, который вы отправили в функцию callback.success()
.
Это проверит, что ваш AuthAPI.Login()
правильно отправит ваш Bus
AuthObject
, который он будет извлекать из "Дооснащения".
(Я понимаю, что вопрос SO был написан некоторое время назад, но поскольку я столкнулся с одной и той же статьей и имел ту же путаницу совсем недавно, я думал, что этот ответ может быть полезен для других.)
Ответ 2
Проблема заключается в том, что вы вызываете verify
в неподходящий момент: целью verify
является проверка того, что взаимодействия с mockApi были такими, какие вы ожидали. Поэтому обычно вы увидите что-то вроде:
authApi.login();
Mockito.verify(mockApi).basicLogin((cb.capture()));
Это также сообщение об ошибке: verify
ожидается basicLogin
, но это не так.
Я тоже прочитал эту статью и почувствовал, что чего-то не хватает. На самом деле я пока еще не обнаружил аргумент. Так что вы не можете с этим справиться:)