2016-02-24 39 views
1

我想測試我的視圖模型在我的應用程序,這裏是構造函數:驗證匿名內部類模擬互動

@Inject 
public SearchUserViewModel(@Named("searchUser") UseCase searchUserUseCase) { 
    this.searchUserUseCase = searchUserUseCase; 
} 

在我的測試中,我創建這樣與嘲笑一個SearchUserUseCase:

Observable error = Observable.error(new Throwable("Error")); 
when(gitHubService.searchUser(MockFactory.TEST_USERNAME_ERROR)).thenReturn(error); 

when(ObserverThread.getScheduler()).thenReturn(Schedulers.immediate()); 
when(SubscriberThread.getScheduler()).thenReturn(Schedulers.immediate()); 

searchUserUseCase = new SearchUserUseCase(gitHubService, SubscriberThread, ObserverThread); 

在我的ViewModel類我有這個片段,我想測試:

public void onClickSearch(View view) { 
    loadUsers(); 
} 

private void loadUsers() { 
    if (username == null) { 
    fragmentListener.showMessage("Enter a username"); 
    } else { 
    showProgressIndicator(true); 
    searchUserUseCase.execute(new SearchUserSubscriber(), username); 
    } 
} 

private final class SearchUserSubscriber extends DefaultSubscriber<SearchResponse> { 

    @Override 
    public void onCompleted() { 
    showProgressIndicator(false); 
    } 

    @Override 
    public void onError(Throwable e) { 
    showProgressIndicator(false); 
    fragmentListener.showMessage("Error loading users"); 
    } 

    @Override 
    public void onNext(SearchResponse searchResponse) { 
    List<User> users = searchResponse.getUsers(); 
    if (users.isEmpty()) { 
     fragmentListener.showMessage("No users found"); 
    } else { 
     fragmentListener.addUsers(users); 
    } 
    } 

} 

最後,在我的測試中,我有這樣的:

@Test 
public void shouldDisplayErrorMessageIfErrorWhenLoadingUsers() { 
    SearchUserViewModel searchUserViewModel = new SearchUserViewModel(searchUserUseCase); 
    searchUserViewModel.setFragmentListener(mockFragmentListener); 
    searchUserViewModel.setUsername(MockFactory.TEST_USERNAME_ERROR); 
    searchUserViewModel.onClickSearch(view); 
    verify(mockFragmentListener).showMessage("Error loading users"); 
} 

我得到這個錯誤來自的Mockito:

Wanted but not invoked: 
fragmentListener.showMessage(
    "Error loading users" 
); 

我不知道這是否是一個很好的測試,但我有點想測試SearchUserSubscriber的一種方式或其他。謝謝

編輯:我發現這個問題類似的問題在這裏:Can't verify mock method call from RxJava Subscriber(仍然沒有回答)和在這裏:Verify interactions in rxjava subscribers。後一個問題是類似的,但不會在單獨的類中執行訂閱(這發生在SearchUserUseCase這裏)。

我也嘗試RobolectricGradleTestRunner而不是MockitoJunitRunner,並更改爲Schedulers.io()和AndroidSchedulers.mainThread(),但我仍然得到相同的錯誤。

嘗試嘲笑SearchUserUseCase而不是GitHubService(感覺更乾淨),但我不確定如何測試訂閱方式,因爲它作爲參數傳遞給void方法execute()在UseCase中。

public void execute(Subscriber useCaseSubscriber, String query) { 
    subscription = buildUseCase(query) 
    .observeOn(postExecutionThread.getScheduler()) 
    .subscribeOn(threadExecutor.getScheduler()) 
    .subscribe(useCaseSubscriber); 
} 

而且buildUseCase()

@Override 
public Observable buildUseCase(String username) throws NullPointerException { 
    if (username == null) { 
    throw new NullPointerException("Query must not be null"); 
    } 
    return getGitHubService().searchUser(username); 
} 
+0

我不知道最初是什麼問題,但它現在正在一些重構來回工作。我最終得到的代碼與問題完全相同。 – hboy

回答

0

如果您正在使用的Mockito,你可以使用ArgumentCaptor,例如可能會得到一個SearchUserSubscriber的保持......

@Captor 
private ArgumentCaptor<SearchUserSubscriber> subscriberCaptor; 

private SearchUserSubscriber getSearchUserSubscriber() { 

    // TODO: ...set up the view model... 
    ... 
    // Execute the code under test (making sure the line 'searchUserUseCase.execute(new SearchUserSubscriber(), username);' gets hit...) 
    viewModel.onClickSearch(view); 

    verify(searchUserUseCase).execute(subscriberCaptor.capture(), any(String.class)); 

    return subscriberCaptor.getValue(); 
} 

現在你可以有測試用例如...

@Test 
public void shouldDoSomethingWithTheSubscriber() { 
    SearchUserSubscriber subscriber = getSearchUserSubscriber(); 

    ... 
} 
+0

問題是SearchUserSubscriber是一個私人類。它確實擴展了DefaultSubscriber,從而擴展了rx.Subscriber。我遵循你的例子,並實現了一個DefaultSubscriber,但除了檢查它是否訂閱之外,我無法從中獲得任何好的信息。我想驗證mockFragmentListener,但這似乎很難... – hboy

1

對我來說,它的工作添加Observable.Transformer<T, T>如下:

void gatherData() { 
    service.doSomeMagic() 
     .compose(getSchedulerTransformer()) 
     .subscribe(view::displayValue); 
} 

private <T> Observable.Transformer<T, T> getSchedulerTransformer() { 
    if (mTransformer == null) { 
     mTransformer = (Observable.Transformer<T, T>) observable -> observable.subscribeOn(Schedulers.io()) 
       .observeOn(AndroidSchedulers.mainThread()); 
    } 

    return mTransformer; 
} 

void setSchedulerTransformer(Observable.Transformer<Observable<?>, Observable<?>> transformer) { 
    mTransformer = transformer; 
} 

,並設置變壓器。我只是通過這樣的:

setSchedulerTransformer(observable -> { 
    if (observable instanceof Observable) { 
     Observable observable1 = (Observable) observable; 
     return observable1.subscribeOn(Schedulers.immediate()) 
       .observeOn(Schedulers.immediate()); 
    } 
    return null; 
}); 

所以只需添加在您的測試@Before方法,並呼籲presenter.setSchedulerTransformer,它應該能夠進行測試。如果你想更詳細的檢查this的答案。

+1

好吧將編輯:) – Makzimalist