Android Interactor测试

时间:2017-04-20 09:07:41

标签: java android unit-testing mockito retrofit2

我有以下课程,我正试图弄清楚如何编写单元测试:

@EBean
public class LoginInteractorImpl implements LoginInteractor {

   private final static String LOGIN_INTERACTOR_THREAD_ID = "LOGIN_INTERACTOR_WORKER";

   private UserRepo mUserRepository;
   private Call<ResponseBody> mCall;

   @Override
   @Background(id = LOGIN_INTERACTOR_THREAD_ID)
   public void login(final String username, final String password, final OnLoginFinishedListener listener) {

      mUserRepository = RetrofitHelper.createClient(UserRepo.class);

      mCall = mUserRepository.doLogin(Credentials.basic(username, password));

      mCall.enqueue(new Callback<ResponseBody>() {
          @Override
          public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
              final int code = response.code();
              if (code == 200) {
                  listener.onSuccess(response.headers().get(""));
              } else if (code == 401) {
                  listener.invalidCredentialsFailure();
              } else if (code >= 400 && code < 500) {
                  listener.invalidCredentialsFailure();
              } else if (code >= 500 && code < 600) {
                  listener.noServerResponseFailure();
              } else {
                  APIError error = ErrorUtils.parseError(response);
                  listener.onError("Unexpected response: code:"
                        + error.getStatusCode()
                        + "message: " + error.getMessage());
              }
          }

           @Override
           public void onFailure(Call<ResponseBody> call, Throwable t) {
              if (t instanceof IOException) {
                  listener.noNetworkFailure();
              } else if(call.isCanceled()) {
                  Log.e(TAG, "request was aborted");
              } else {
                  listener.onError(t.getMessage());
              }
           }
       });
   }

   @Override
   public void cancel() {
     mCall.cancel();
     BackgroundExecutor.cancelAll(LOGIN_INTERACTOR_THREAD_ID, true);
     }
}

使用Retrofit我正在调用我的webservice进行身份验证,webservice应该返回一个Authtoken供以后使用。我只是无法掌握如何测试这个。我尝试使用Mockito创建解决方案,但我无法弄清楚如何测试登录方法的逻辑。是否有任何关于Mockito / Retrofit的专家可以指导我更接近工作解决方案?

1 个答案:

答案 0 :(得分:3)

在尝试任何单元测试之前,我会重构一些事情:

1)enqueue方法中创建的匿名类创建一个显式的Callback类。让我们称之为LoginCallback

public class LoginCallback implements Callback{
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            final int code = response.code();
            if (code == 200) {
            ...
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
         if (t instanceof IOException) {
            listener.noNetworkFailure();
           ...
    }
}

现在,您对这两种方法逻辑执行隔离单元测试。

2)将静态方法调用移动到包级别方法。你最终会得到这样的东西:

public class LoginInteractorImpl implements LoginInteractor {

   public void login(final String username, final String password, final OnLoginFinishedListener listener) {

     mUserRepository = createClient();

     mCall = mUserRepository.doLogin(getCredentials(username,password));

     mCall.enqueue(new LoginCallback());
   }

    UserRepo createClient(){
       RetrofitHelper.createClient(UserRepo.class)
    }

    Credentials getCredentials(String username, String password){
        return Credentials.basic(username, password)
    }
}

3)单元测试login方法

@RunWith(JunitMockitoRunner.class)
public class TestClass{

    @Spy
    private LoginInteractorImpl loginInterceptor=  new LoginInteractorImpl();

    @Mock
    private UserRepo mUserRepositoryMock;

    @Mock
    private Call<ResponseBody> mCallMock;

    @Mock
    private Credentials credentialsMock;

    public void shouldEnqueueWhenLogin(){
        // Arrange
        String username = "name";
        String password = "pass";
        Mockito.doReturn(mUserRepositoryMock).when(loginInterceptor).createClient();

       Mockito.doReturn(credentialsMock).when(loginInterceptor).when(getCredentials(username, password));

        Mockito.doReturn(mCallMock).when(mUserRepositoryMock).doLogin(credentialsMock);

        // Act
        loginInterceptor.login(username, password);

        // Assert that proper callback has been passed to enqueue
        verify(mCallMock).enqueue(Mockito.any(LoginCallback.class));
    }
 }