2016-05-20 15 views
7

Ich brauche ein paar Tipps, wie man eine Pause api verspotten kann. Meine Anwendung ist in MVP-Architektur.Unit Test von Retrofit 2 api Anruf mit Mockito

Meine Schnittstelle für API:

public interface MyAPI { 

    @GET("{cmd}/{userName}/{password}") 
    Observable<Response> login(
     @Path("cmd") String cmd, 
     @Path("userName") String userName, 
     @Path("password") String password 
    ); 

Mein Service:

public class MyService implements IService { 

    private static MyService mInstance = new MyService(); 
    private MyAPI mApi; 

    public static MyService getInstance() { 
     return mInstance; 
    } 

    private MyService() { 

     OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); 
     httpClientBuilder.connectTimeout(Config.DEFAULT_TIMEOUT, TimeUnit.SECONDS); 

     Retrofit retrofit = new Retrofit.Builder() 
      .baseUrl(Config.kBaseUrl) 
      .addConverterFactory(GsonConverterFactory.create()) 
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
      .client(httpClientBuilder.build()) 
      .build(); 

     this.mApi = retrofit.create(MyAPI.class); 
    } 

    public void login(
     Subscriber<Response> subscriber, 
     String userName, 
     String password) { 
     mApi.login(Config.kLoginCmd,userName,password) 
      .subscribeOn(Schedulers.io()) 
      .unsubscribeOn(Schedulers.io()) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .subscribe(subscriber); 
    } 

Meine Moderator Klasse:

public class LoginPresenter implements LoginContract.Presenter { 

    LoginContract.View mView; 
    IService mService; 
    ISession mSession; 

    public LoginPresenter(LoginContract.View loginView, IService service, ISession session) { 
     mView = loginView; 
     mService = service; 
     mSession = session; 
    } 

    @Override 
    public void login(String email, String password) { 

     Subscriber<Response> subscriber = new Subscriber<Response>() { 
      @Override 
      public void onCompleted() { 
       mView.showLoading(false); 
      } 

      @Override 
      public void onError(Throwable e) { 
       mView.showError(e.getLocalizedMessage()); 
      } 

      @Override 
      public void onNext(Response response) { 
       if (response.getResults().getStatus().equalsIgnoreCase(Config.kResultCodeOK)) { 
        mView.loginSuccess(); 
       } else { 
        mView.showError(response.getResults().getStatus().getErrmsg()); 
       } 
      } 
     }; 

     mView.showLoading(true); 
     mService.login(
      subscriber, 
      email, 
      password); 
    } 

Es gibt einen anderen Weg, um meine Moderator zu testen, indem Sie einen Mock-Service zu schreiben . Aber ich mag das nicht so sehr und ich denke Mockito könnte helfen.

Hier ist mein Test-Klasse:

public class LoginPresenterMockTest { 

    private LoginPresenter mLoginPresenter; 

    @Mock 
    LoginContract.View view; 
    @Mock 
    IService service; 
    @Mock 
    ISession session; 

    @Before 
    public void setup() throws Exception { 
     MockitoAnnotations.initMocks(this); 
     mLoginPresenter = new LoginPresenter(view, service, session); 
    } 

    @Test 
    public void testLoginWithCorrectUserNameAndPassword() throws Exception { 
     mLoginPresenter.login("[email protected]","password"); 
     verify(view).loginSuccess(); 
    } 

} 

Was ich tun möchte, ist ich die Antwort Datenanruf loginSuccess verspotten(), wenn die Antwort richtig ist.

Natürlich wird mein aktueller Test nicht funktionieren. Ich brauche ein paar Ratschläge, wie ich mich darüber lustig machen kann? Irgendeine Idee? Vielen Dank.

Antwort

5

Sie können es in der nächsten Art und Weise tun:

@Test 
public void testLoginWithCorrectUserNameAndPassword() throws Exception { 
    // create or mock response object 
    when(service.login(anyString(), anyString(), anyString).thenReturn(Observable.just(response)); 
    mLoginPresenter.login("[email protected]","password"); 
    verify(view).loginSuccess(); 
} 

@Test 
public void testLoginWithIncorrectUserNameAndPassword() throws Exception { 
    // create or mock response object 
    when(service.login(anyString(), anyString(), anyString).thenReturn(Observable.<Response>error(new IOException())); 
    mLoginPresenter.login("[email protected]","password"); 
    verify(view).showError(anyString); 
} 
+0

'' 'Mockito.when (service.login (any(), anyString(), anyString()). thenReturn (Observable.just (response)); '' 'Wie den ersten Parameter zu spezifizieren? Es ist Abonnent . Ich kann es nicht zu irgendeinem(). Was sollte Ich tue das? Danke –

+0

Entschuldigung, ich habe nicht bemerkt, dass Sie Teilnehmer übergeben. Ich denke, es ist besser, c hange deine Service-Methode, die sie Observable zurückgibt und abonniere sie in der Presenter-Klasse. In diesem Fall wird der angegebene Code funktionieren. Ansonsten solltest du mApi mokieren. –

+0

Behebung des Problems durch ** ArgumentCaptor ** –

3

Vielen Dank für @Ilya Tretjakow, kam ich diese Lösung aus:

private ArgumentCaptor<Subscriber<Response>> subscriberArgumentCaptor; 

@Test 
public void testLoginWithCorrectUserNameAndPassword() throws Exception { 
    mLoginPresenter.login("[email protected]","password"); 
    // create the mock Response object 
    Response response = ...... 

    verify(service, times(1)).login(
     subscriberArgumentCaptor.capture(), 
     stringUserNameCaptor.capture(), 
     stringPasswordCaptor.capture() 
    ); 

    subscriberArgumentCaptor.getValue().onNext(response); 
    verify(view).loginSuccess(); 
}