I'm developing application based on MVP pattern using retrofit to perform networking. I want to unit test my presenter but it fails.
In my app dataView implements DataView which is mocked by Mockito. In
DataPresenter in onViewCreated method MyApi instance is get from MyApplication and it performs request. Anonymous Subscriber<Data> onNext calls showData(Data data) on dataView. Unfortunatelly Mockito.verify(dataView).showData(data) fails the test. I mocked retrofit client by my self to response in deterministic way.
Code below:
public class DataFragment extends ProgressFragment implements DataView {
protected DataPresenter mDataPresenter;
//[...] initialization arguments boilerplate etc.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mDataPresenter.onViewCreated(mId);
//[...]
}
#Override
public void startLoading() {
setContentShown(false);
}
#Override
public void stopLoading() {
setContentShown(true);
}
#Override
public void showData(Data data) {
setContentEmpty(false);
//[...] present data
}
#Override
public void showError() {
setContentEmpty(true);
setEmptyText(R.string.unknown_error);
}
}
In DataPresenter:
#Override
public void onViewCreated(long id) {
getView().startLoading();
MyApplication.getInstance().getMyApi().checkIn(User.getUser().getFormattedTokenForRequest(),
(int) id).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(new Subscriber<Data>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
getView().showError();
getView().stopLoading();
}
#Override
public void onNext(Data data) {
getView().showData(data);
getView().stopLoading();
}
});
;
}
My test case:
public static final String GOOD_RESPONSE = "[Data in JSON]"
public static final int GOOD_STATUS = 201;
#Mock
DataView mDataView;
#Mock
MyApplication app;
#Mock
SharedPreferencesManager mSharedPreferencesManager;
DataPresenter mDataPresenter;
#Before
public void setUp() throws Exception {
mDataPresenter = new DataPresenterImpl(mDataView);
MyApplication.setInstance(app);
Mockito.when(app.getSharedPreferencesManager()).thenReturn(mSharedPreferencesManager);
Mockito.when(mSharedPreferencesManager.getUser()).thenReturn(null);
}
#Test
public void testCase() throws Exception {
RestAdapter adapter = (new RestAdapter.Builder()).setEndpoint(URL)
.setClient(new MockClient(GOOD_RESPONSE, GOOD_STATUS))
.build();
Mockito.when(app.getMyApi()).thenReturn(adapter.create(MyApi.class));
mCheckInPresenter.onViewCreated(3);
Mockito.verify(checkInView).startLoading();
Mockito.verify(checkInView).showData(new Data());
}
Test fails on "Wanted but not invoked:
dataView.showData(..." .
What is interesting Response execute() is called in MockClient but onNext(Data data) in subscriber included in DataPresenterImpl is not. Any ideas? I guess it is a problem with request being asynchronous.
The problem is that the work is being sent to a different thread and mockito cant verify whats going on. My solution to this would be to create a scheduler factory and mock it out and return the main thread for tests
like these. Something like:
public class schedulerFactory {
public Scheduler io() {
return Schedulers.io();
}
//etc
}
then in your test you would write something like this:
#Mock SchedulerFactory factory
#Before
public void setUp() {
when(factory.io()).thenReturn(Schedulers.mainThread());
}
in general its a good idea to run all the code in the same thread for testing
Related
I know it was asked before, but i am currently diving into testing and i have the struggle to unit test presenter in MVP pattern with Mockito
My code setup:
Item class
public class ItemJSON {
#SerializedName("title")
String textHolder;
#SerializedName("id")
int factNumber;
public ItemJSON(String factText, int factNumber) {
this.textHolder = factText;
this.factNumber = factNumber;
}
//getters and setters
}
Contractor:
public interface Contractor {
interface Presenter {
void getPosts();
}
interface View {
//parse data to recyclerview on Succesfull call.
void parseDataToRecyclerView(List<ItemJSON> listCall);
void onResponseFailure(Throwable throwable);
}
interface Interactor {
interface onGetPostsListener {
void onSuccessGetPostCall(List<ItemJSON> listCall);
void onFailure(Throwable t);
}
void getPosts(onGetPostsListener onGetPostsListener);
}
}
API class:
#GET("posts")
Call<List<ItemJSON>> getPost();
Interactor class:
public class InteractorImpl implements Contractor.Interactor{
#Override
public void getPosts(onGetPostsListener onGetPostsListener) {
// NetworkService responsible for seting up Retrofit2
NetworkService.getInstance().getJSONApi().getPost().enqueue(new Callback<List<ItemJSON>> () {
#Override
public void onResponse(#NonNull Call<List<ItemJSON>> call, #NonNull Response<List<ItemJSON>> response) {
Log.d("OPERATION #GET","CALLBACK SUCCESSFUL");
onGetPostsListener.onSuccessGetPostCall (response.body ());
}
#Override
public void onFailure(#NonNull Call<List<ItemJSON>>call, #NonNull Throwable t) {
Log.d("OPERATION #GET","CALLBACK FAILURE");
onGetPostsListener.onFailure (t);
}
});
}
Presenter class:
public class PresenterImpl implements Contractor.Presenter, Contractor.Interactor.onGetPostsListener {
private final Contractor.View view;
private final Contractor.Interactor interactor;
public PresenterImpl (Contractor.View view,Contractor.Interactor interactor){
this.view = view;
this.interactor = interactor;
}
#Override
public void getPosts() {
interactor.getPosts (this);
}
#Override
public void onSuccessGetPostCall(List<ItemJSON> listCall) {
view.parseDataToRecyclerView (listCall);
}
}
So i try to ran some unit test on presenter, but they constanlty fail and i keep getting next error
Wanted but not invoked Actually, there were zero interactions with this mock
Unit test class:
#RunWith (MockitoJUnitRunner.class)
public class ApiMockTest{
#Mock
Contractor.View view;
private PresenterImpl presenter;
#Captor
ArgumentCaptor<List<ItemJSON>> jsons;
#Before
public void setUp() {
MockitoAnnotations.openMocks (this);
presenter = new PresenterImpl (view,new InteractorImpl ());
}
#Test
public void loadPost() {
presenter.getPosts ();
verify(view).parseDataToRecyclerView (jsons.capture ());
Assert.assertEquals (2, jsons.capture ().size ());
}
}
I try to understand what i am doing wrong and how to fix this issue, but as for now i am ran out of ideas. I will aprecciate any help.
Thanks in the adavance
UPD: in all cases in main activity presenter get called in onClick
Main Activity class:
public class MainActivity extends AppCompatActivity implements Contractor.View {
public Contractor.Presenter presenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
presenter = new PresenterImpl (this,new InteractorImpl ());
binding.getButton.setOnClickListener(view ->presenter.getPosts () );
...//code
#Override
public void parseDataToRecyclerView(List<ItemJSON> listCall) {
adapter.updateList(listCall); //diff call to put data into recyclerview adapter
}
}
}
I ran into this situation also, even using the mockk library. The problem is that your method is an interface method. You need to actually call it from a view which has implemented this interface.
I have a method that makes an API Call after 1 sec. I use Handler.postdelayed to implement this.
Now I am trying to verify if the API call is being made with a unit test.
#Mock
private PlanRepository planRepository;
#Mock
private CreatePlanContract.View view;
private CreatePlanContract.Presenter presenter;
#Captor
private ArgumentCaptor<ListResponseCallback<IntersectingList>> listCaptor;
....
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
presenter = new CreatePlanPresenter(resourceProvider, sessionContext, planRepository);
presenter.start();
presenter.setView(view);
...
}
#Test
public void testOnCameraIdleGetListEnabled(){
presenter.onCameraIdle(true);
verify(planRepository,times(1))
.getList(listCaptor.capture());
}
This is the method in presenter that I want to test:
class PlanPresenter implements PlanContract.Presenter{
private Handler mHandler = new Handler();
private Runnable mRunnable = this::fetchList;
private WeakReference<CreatePlanContract.View> createPlanView;
private ListResponseCallback<IntersectingList> listListener = new ListResponseCallback<Intersectinglist>() {
#Override
public void onSuccess(#NonNull List<IntersectingList> list) {
Log.d(TAG, "callback: success resp came");
if(createPlanView.get() != null)
createPlanView.get().renderList(list);
}
#Override
public void onError(int i, #NonNull String s, #NonNull APIResponseBody apiResponseBody, #Nullable Exception e) {
Log.d(TAG, "callback: error resp came Auth");
}
};
#Override
public void start() {
//some initilizations
}
#Override
public void setView(#NonNull CreatePlanContract.View view) {
this.createPlanView = new WeakReference<>(view);
}
#Override
public void onCameraIdle(){
mHandler.postDelayed(mRunnable,1000);
}
private void fetchList(){
//this the method to be verified
planRepository.getList(listListener);
}
}
But since the api call is being made after 1 sec, the test is failing.
What I have tried:
I tried following this link and use doAnswer() but I was unsuccessful.
I thought of using thread.sleep() which seems like an awful approach for this problem(also read that its a bad approach)
PS: I am a noob to testing.
I am using JUnit 4 and mockito
Try adding the following line, before calling the method from the presenter class
given(presenter.handler.postDelayed(any(Runnable.class), anyLong())).willReturn(true);
As an example
given(presenter.handler.postDelayed(any(Runnable.class), anyLong())).willReturn(true);
presenter.doSomething();
I'm developing an Android application, trying to follow Clean Architecture / MVP guidelines.
I'm currently wiriting Unit Tests for my presenters, but I'm stuck with the call to the Interactor/UseCase, that takes a DisposableObserver as a parameter.
What I would like to test is that the correct behavior is called when the interactor invokes OnNext or OnError for example (hide/show loading indicator...).
I don't know how to 'mock' the behavior of the Observable in my use Case, as it is built when the execute() method is called, using a protected method.
Below are some portions of code:
Presenter
#ConfigPersistent
public class ContentPresenter extends BasePresenter<ContentContract.View> implements ContentContract.Presenter {
#Inject
GetContent mGetContentUseCase;
#Inject
ContentViewModelMapper mContentViewModelMapper;
#Inject
public ContentPresenter() {
}
#Override
public void fetchContent(long contentId) {
getMvpView().showProgress();
mGetContentUseCase.execute(contentId, new ContentObserver());
}
private final class ContentObserver extends DisposableObserver<Content> {
#Override
public void onNext(Content content) {
getMvpView().hideProgress();
getMvpView().showContentInfo(mContentViewModelMapper.map2(content));
}
#Override
public void onError(Throwable e) {
getMvpView().hideProgress();
Timber.e(e.getMessage());
}
#Override
public void onComplete() {
getMvpView().hideProgress();
}
}
}
Interactor/UseCase
public class GetContent extends UseCaseObservableWithParameter<Long, Content, Repository> {
#Inject
public GetContent(Repository repository,
#Named("Thread") Scheduler threadScheduler,
#Named("PostExecution") Scheduler postExecutionScheduler) {
super(repository, threadScheduler, postExecutionScheduler);
}
#Override
protected Observable<Content> buildObservable(Long id) {
return repository.getContentById(id);
}
}
BaseUseCase
public abstract class UseCaseObservableWithParameter<REQUEST_DATA, RESPONSE_DATA, REPOSITORY> extends UseCase<Observable<RESPONSE_DATA>, REQUEST_DATA, REPOSITORY> {
public UseCaseObservableWithParameter(REPOSITORY repository, Scheduler threadScheduler, Scheduler postExecutionScheduler) {
super(repository, threadScheduler, postExecutionScheduler);
}
protected abstract Observable<RESPONSE_DATA> buildObservable(REQUEST_DATA requestData);
public void execute(REQUEST_DATA requestData, DisposableObserver<RESPONSE_DATA> useCaseSubscriber) {
this.disposable.clear();
this.disposable.add(
this.buildObservable(requestData)
.subscribeOn(threadScheduler)
.observeOn(postExecutionScheduler)
.subscribeWith(useCaseSubscriber)
);
}
}
After a good night's sleep, this is what I came up with:
#Test
#SuppressWarnings("unchecked")
public void testShowContents() {
doAnswer((i) -> {
// Do stuff with i.getArguments() here
DisposableObserver<Content> d = i.getArgument(1);
Observable.just(mock(Content.class)).subscribeWith(d);
return null;
})
.when(mGetContentUseCase)
.execute(eq(AppTestData.TEST_LONG_ID_1), any(DisposableObserver.class));
contentPresenter.fetchContent(AppTestData.TEST_LONG_ID_1);
Mockito.verify(view, Mockito.times(1)).showContentInfo(Mockito.any());
InOrder orderVerifier = Mockito.inOrder(view);
orderVerifier.verify(view).showProgress();
orderVerifier.verify(view).hideProgress();
orderVerifier.verify(view).showContentInfo(any());
}
#Test
#SuppressWarnings("unchecked")
public void testShowContentsError() {
doAnswer((i) -> {
// Do stuff with i.getArguments() here
DisposableObserver<Content> d = i.getArgument(1);
Observable.<Content>error(new Throwable()).subscribeWith(d);
return null;
})
.when(mGetContentUseCase)
.execute(eq(AppTestData.TEST_LONG_ID_1), any(DisposableObserver.class));
contentPresenter.fetchContent(AppTestData.TEST_LONG_ID_1);
Mockito.verify(view, Mockito.times(1)).showErrorMessage(Mockito.any());
InOrder orderVerifier = Mockito.inOrder(view);
orderVerifier.verify(view).showProgress();
orderVerifier.verify(view).hideProgress();
orderVerifier.verify(view).showErrorMessage(any());
}
I'm writing Unit tests for my Android App using Mockito.
I'm using dagger 2 to switch between a Mock Client and a real client:
#Module
public class ApiModule {
private boolean mMockMode;
#Provides
#Singleton
Client provideClient() {
if (mMockMode) {
return Mockito.mock(Client.class);
}
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.networkInterceptors().add(new StethoInterceptor());
return new OkClient(okHttpClient);
}
}
The client is injected into the tests like this:
public class MainActivityTest extends ActivityInstrumentationTestCase2<BaseActivity> {
#Inject
Client client;
public MainActivityTest() {
super(MainActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
App app = (App) getInstrumentation().getTargetContext().getApplicationContext();
app.setMockMode(true);
app.component().inject(this);
}
#Test
public void testWithActualCall(){
//code...
}
#Test
public void testWithMockCall(){
//code...
}
#Override
protected void tearDown() throws Exception {
App.getInstance().setMockMode(false);
}
}
As can be seen from the code, there are some tests that I wish to do with a mock api and others that I wish to do with the real api. In order to do this, I need to know for which test setUp() is being called so that I can change the argument of setMockMode(boolean) accordingly.
Is there a way I can find out which test is being setUp()?
Split up the tests into 2 classes, one with all tests that use the mocked API, the other with the real API.
Use what you have as a base class, move the value of mockMode into a method and then override that method in the other class:
public class MainActivityMockApiTest extends ActivityInstrumentationTestCase2<BaseActivity> {
...
#Override
protected void setUp() throws Exception {
...
app.setMockMode(isMockMode());
...
}
protected boolean isMockMode() {
// overridden in MainActivityRealApiTest
return true;
}
...
}
I recently converted my application from using async tasks to rxjava. Now, my espresso tests no longer wait for my data calls to complete due to espresso not having an idling resources for rxjava. I noticed that you can make custom idling resources but I can't figure out how to make it work with rxJava Schedulers, Scheduler.io specifically. Any help/best practice would be greatly appreciated.
Here is how I solved the problem:
IdlingResource implementation:
public class IdlingApiServiceWrapper implements MyRestService, IdlingResource {
private final MyRestService api;
private final AtomicInteger counter;
private final List<ResourceCallback> callbacks;
public IdlingApiServiceWrapper(MyRestService api) {
this.api = api;
this.callbacks = new ArrayList<>();
this.counter = new AtomicInteger(0);
}
public Observable<MyData> loadData(){
counter.incrementAndGet();
return api.loadData().finallyDo(new Action0() {
#Override
public void call() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
counter.decrementAndGet();
notifyIdle();
}
});
}
});
}
#Override public String getName() {
return this.getClass().getName();
}
#Override public boolean isIdleNow() {
return counter.get() == 0;
}
#Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
callbacks.add(resourceCallback);
}
private void notifyIdle() {
if (counter.get() == 0) {
for (ResourceCallback cb : callbacks) {
cb.onTransitionToIdle();
}
}
}
}
and here is my test:
public class MyActivityTest extends ActivityInstrumentationTestCase2<MyActivity> {
#Inject
IdlingApiServiceWrapper idlingApiWrapper;
#Override
public void setUp() throws Exception {
//object graph creation
super.setUp();
getActivity();
Espresso.registerIdlingResources(idlingApiWrapper);
}
public void testClickOpenFirstSavedOffer() throws Exception {
onData(is(instanceOf(DataItem.class)))
.atPosition(0)
.perform(click());
}
}
I used Dagger for dependency injection.
Wrote a little integration piece between RxJava Plugins and Espresso. Hope this helps someone else.
https://gist.github.com/digitalbuddha/d886eae1578bca78b9bf
Edit:
There is a much easier way to accomplish this task. Add the following rule to your tests
public class AsyncTaskSchedulerRule implements TestRule {
final Scheduler asyncTaskScheduler = Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR);
#Override
public Statement apply(Statement base, Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
RxJavaHooks.setOnIOScheduler(scheduler -> asyncTaskScheduler);
RxJavaHooks.setOnComputationScheduler(scheduler -> asyncTaskScheduler);
RxJavaHooks.setOnNewThreadScheduler(scheduler -> asyncTaskScheduler);
try {
base.evaluate();
} finally {
RxJavaHooks.reset();
}
}
};
}
}
I am currently using this implementation. Its easier and works very well for me so far: https://github.com/rosshambrick/RxEspresso