使用 Mockito 测试 MVP Android 应用程序
Testing an MVP Android Application with Mockito
我正在尝试对基本 Android 应用程序进行一些单元测试。它只是使用改造登录到某些 WS 我的应用程序具有 MVP 模式。
我在做什么?
调用演示层这将调用交互器,在这里我将调用我的服务
@Override
public void doLogin(String user, String pwd, final LoginListener loginListener) {
try {
final LoginRequest request = new LoginRequest();
request.setEmpleado(user);
request.setPwd(pwd);
Callback<LoginResponse> callback = new Callback<LoginResponse>() {
@Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if(response != null && response.isSuccessful() && response.body() != null) {
if("00".equals(response.body().getCodigo())) {
loginListener.authOK();
} else {
loginListener.showError();
}
} else {
loginListener.showError();
}
}
@Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
"+t.getMessage()+" "+t.getCause());
if(t instanceof SocketTimeoutException) {
loginListener.showError();
} else {
loginListener.showError();
}
}
};
WSLogin wsLogin = RetrofitClient.getInstance().getRetrofit().create(WSLogin.class);
wsLogin.autenticar(request).enqueue(callback);
} catch (Exception e) {
loginListener.showError();
e.printStackTrace();
}
它调用了我的服务,但我从未进入回调
测试
package com.arleckk.loginmvpci.login;
import com.arleckk.loginmvpci.login.presenter.LoginListener;
import com.arleckk.loginmvpci.login.presenter.LoginPresenter;
import com.arleckk.loginmvpci.login.presenter.LoginPresenterImpl;
import com.arleckk.loginmvpci.login.view.LoginView;
import com.arleckk.loginmvpci.model.LoginResponse;
import com.arleckk.loginmvpci.network.WSLogin;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.PowerMockRunner;
import java.io.IOException;
import retrofit2.Call;
import retrofit2.Response;
import static org.junit.Assert.assertEquals;
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.net.ssl.*")
public class LoginTest {
@Mock private LoginView loginView;
@Mock private LoginPresenter loginPresenter;
@Mock private LoginListener loginListener;
@Mock private Call<LoginResponse> loginResponseCall;
Response<LoginResponse> loginResponseResponse;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
loginPresenter = new LoginPresenterImpl(loginView);
}
@Test
public void testOK() throws IOException {
loginPresenter.doLogin("TEST", "TEST1234");
}
}
另一个问题是:我真的在做单元测试吗?我的意思是单元测试只测试 "Unit" 的代码。
我期待一个 LoginResponse 对象,然后比较它,如果它等于“00”,则成功
不,你不是。有几个原因。首先,你在这里没有测试。你没有一个断言。无论发生什么,您的代码都会说通过。所以这不是测试。测试是说使用有效登录名调用 doLogin,并确保调用 loginListener.authOK()。然后是另一个使用错误密码的测试,并检查是否调用了 showError。没有它,你所拥有的一切都是在浪费时间。
其次 - 这对于单元测试来说范围太广了。对于单元测试,您应该检查最小的代码单元是否有效。在这里,您正在检查您的整个网络堆栈和您的服务器是否都正常工作。那太过分了。并且单元测试永远不应该依赖于外部服务器的工作,这只会导致不稳定的测试——类似的东西应该在集成套件中。
您目前的代码未针对测试进行优化。如果是的话——你就不会通过代码中的单例来创建改造客户端。您会将其传递给 doLogin。这样你就可以在测试中传递一个模拟,该模拟可能 return 一个虚假的响应,然后测试你的代码是否可以正确识别虚假的成功和失败响应,删除服务器依赖性但测试所有功能.
我正在尝试对基本 Android 应用程序进行一些单元测试。它只是使用改造登录到某些 WS 我的应用程序具有 MVP 模式。
我在做什么?
调用演示层这将调用交互器,在这里我将调用我的服务
@Override
public void doLogin(String user, String pwd, final LoginListener loginListener) {
try {
final LoginRequest request = new LoginRequest();
request.setEmpleado(user);
request.setPwd(pwd);
Callback<LoginResponse> callback = new Callback<LoginResponse>() {
@Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if(response != null && response.isSuccessful() && response.body() != null) {
if("00".equals(response.body().getCodigo())) {
loginListener.authOK();
} else {
loginListener.showError();
}
} else {
loginListener.showError();
}
}
@Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
"+t.getMessage()+" "+t.getCause());
if(t instanceof SocketTimeoutException) {
loginListener.showError();
} else {
loginListener.showError();
}
}
};
WSLogin wsLogin = RetrofitClient.getInstance().getRetrofit().create(WSLogin.class);
wsLogin.autenticar(request).enqueue(callback);
} catch (Exception e) {
loginListener.showError();
e.printStackTrace();
}
它调用了我的服务,但我从未进入回调
测试
package com.arleckk.loginmvpci.login;
import com.arleckk.loginmvpci.login.presenter.LoginListener;
import com.arleckk.loginmvpci.login.presenter.LoginPresenter;
import com.arleckk.loginmvpci.login.presenter.LoginPresenterImpl;
import com.arleckk.loginmvpci.login.view.LoginView;
import com.arleckk.loginmvpci.model.LoginResponse;
import com.arleckk.loginmvpci.network.WSLogin;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.PowerMockRunner;
import java.io.IOException;
import retrofit2.Call;
import retrofit2.Response;
import static org.junit.Assert.assertEquals;
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.net.ssl.*")
public class LoginTest {
@Mock private LoginView loginView;
@Mock private LoginPresenter loginPresenter;
@Mock private LoginListener loginListener;
@Mock private Call<LoginResponse> loginResponseCall;
Response<LoginResponse> loginResponseResponse;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
loginPresenter = new LoginPresenterImpl(loginView);
}
@Test
public void testOK() throws IOException {
loginPresenter.doLogin("TEST", "TEST1234");
}
}
另一个问题是:我真的在做单元测试吗?我的意思是单元测试只测试 "Unit" 的代码。
我期待一个 LoginResponse 对象,然后比较它,如果它等于“00”,则成功
不,你不是。有几个原因。首先,你在这里没有测试。你没有一个断言。无论发生什么,您的代码都会说通过。所以这不是测试。测试是说使用有效登录名调用 doLogin,并确保调用 loginListener.authOK()。然后是另一个使用错误密码的测试,并检查是否调用了 showError。没有它,你所拥有的一切都是在浪费时间。
其次 - 这对于单元测试来说范围太广了。对于单元测试,您应该检查最小的代码单元是否有效。在这里,您正在检查您的整个网络堆栈和您的服务器是否都正常工作。那太过分了。并且单元测试永远不应该依赖于外部服务器的工作,这只会导致不稳定的测试——类似的东西应该在集成套件中。
您目前的代码未针对测试进行优化。如果是的话——你就不会通过代码中的单例来创建改造客户端。您会将其传递给 doLogin。这样你就可以在测试中传递一个模拟,该模拟可能 return 一个虚假的响应,然后测试你的代码是否可以正确识别虚假的成功和失败响应,删除服务器依赖性但测试所有功能.