How to write unit test case for API for android?

Viewed 2112

I want to write a unit test cases for my piece of code while developing and before build the APK need to pass all the unit test cases also.Please suggest the me.

2 Answers

For writing test cases you need to follow some architecture like MVP or MVVM, You also need to use Junit and Mockito testing framework Here you can find example.

Here is an simple example may be it can help you. Here I am using Retrofit for networking

Activity

package com.ram.com.mvp_sample;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.ram.com.mvp_sample.modal.RemoteRepository;
import com.ram.com.mvp_sample.modal.Repository;
import com.ram.com.mvp_sample.modal.pojo.Example;

import java.util.List;

/**
 * A login screen that offers login via email/password.
 */
public class ImageListActivity extends AppCompatActivity implements Contract.View {


    private Contract.Presenter presenter;
    private ProgressBar mProgressView;
    private RecyclerView imageList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_list);
        presenter = new Presenter(this, Repository.getInstance(RemoteRepository.getInstance()));
        mProgressView = findViewById(R.id.login_progress);
        imageList = findViewById(R.id.image_list);
        presenter.getImageList(new AppNetworkStatus(this));

    }


    @Override
    public void showProgressBar(boolean show) {
        mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
    }

    @Override
    public void showImageList(List<Example> example) {
        ImageListAdapter adapter = new ImageListAdapter(example);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        imageList.setLayoutManager(layoutManager);
        imageList.setAdapter(adapter);
    }

    @Override
    public void showError(Object errorCode) {
        Toast.makeText(this, errorCode.toString(), Toast.LENGTH_LONG).show();
    }

    @Override
    public void setPresenter(Contract.Presenter presenter) {
        this.presenter = presenter;
    }
}

Repository class: it will interact with RemoteRepository

package com.ram.com.mvp_sample;

import com.ram.com.mvp_sample.modal.DataSource;
import com.ram.com.mvp_sample.modal.Repository;
import com.ram.com.mvp_sample.modal.pojo.Example;

import java.util.List;

public class Presenter implements Contract.Presenter {

private Contract.View view;
private Repository repository;

public Presenter(Contract.View view, Repository storesRepository) {
    this.view = view;
    this.repository = storesRepository;
    this.view.setPresenter(this);
}

@Override
public void getImageList(NetworkStatus networkStatus) {
    view.showProgressBar(true);
    repository.getList(networkStatus, new DataSource.OnResponseCallBackListener() {
        @Override
        public void onSuccess(List<Example> data) {
            view.showProgressBar(false);
            view.showImageList(data);
        }

        @Override
        public void onError(Object error) {
            view.showProgressBar(false);
            view.showError(error);
        }
    });
}

@Override
public void start() {

}
}

RemoteRepository class: It will directly intrect with Retrofit here

 package com.ram.com.mvp_sample.modal;

import com.ram.com.mvp_sample.APIClient;
import com.ram.com.mvp_sample.ApiInterface;
import com.ram.com.mvp_sample.NetworkStatus;
import com.ram.com.mvp_sample.modal.pojo.Example;

import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class RemoteRepository implements DataSource {

private static RemoteRepository INSTANCE = null;

private RemoteRepository() {
}

public static RemoteRepository getInstance() {
    if (INSTANCE == null) {
        INSTANCE = new RemoteRepository();
    }
    return INSTANCE;
}

@Override
public void getList(NetworkStatus networkStats, final OnResponseCallBackListener onResponseCallBackListener) {

    ApiInterface apiInterface = APIClient.getClient().create(ApiInterface.class);

    Call<List<Example>> call1 = apiInterface.getImageList();
    call1.enqueue(new Callback<List<Example>>() {
        @Override
        public void onResponse(Call<List<Example>> call, Response<List<Example>> response) {
            onResponseCallBackListener.onSuccess(response.body());

        }

        @Override
        public void onFailure(Call<List<Example>> call, Throwable t) {
            onResponseCallBackListener.onError(t.toString());

        }
    });
}
}

Presenter class : Presenter is responsible for communicating with Repository and View

package com.ram.com.mvp_sample;

import com.ram.com.mvp_sample.modal.DataSource;
import com.ram.com.mvp_sample.modal.Repository;
import com.ram.com.mvp_sample.modal.pojo.Example;

import java.util.List;

public class Presenter implements Contract.Presenter {

private Contract.View view;
private Repository repository;

public Presenter(Contract.View view, Repository storesRepository) {
    this.view = view;
    this.repository = storesRepository;
    this.view.setPresenter(this);
}

@Override
public void getImageList(NetworkStatus networkStatus) {
    view.showProgressBar(true);
    repository.getList(networkStatus, new DataSource.OnResponseCallBackListener() {
        @Override
        public void onSuccess(List<Example> data) {
            view.showProgressBar(false);
            view.showImageList(data);
        }

        @Override
        public void onError(Object error) {
            view.showProgressBar(false);
            view.showError(error);
        }
    });
}

@Override
public void start() {

}
}

Test cases for presenter class

package com.ram.com.mvp_sample;

import com.ram.com.mvp_sample.modal.DataSource;
import com.ram.com.mvp_sample.modal.Repository;
import com.ram.com.mvp_sample.modal.pojo.Example;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class PresenterTest {

private Presenter presenter;

@Mock
private Repository repository;

@Mock
private Contract.View view;

@Mock
private NetworkStatus networkStatus;

@Captor
private ArgumentCaptor<NetworkStatus> networkStatusArgumentCaptor;

@Captor
private ArgumentCaptor<DataSource.OnResponseCallBackListener> callBackListenerArgumentCaptor;

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);

    presenter = new Presenter(view, repository);
}

// Positive test
@Test
public void getImageList() {

    when(networkStatus.isOnline()).thenReturn(true);

    presenter.getImageList(networkStatus);

    verify(repository).getList(networkStatusArgumentCaptor.capture(), callBackListenerArgumentCaptor.capture());
    callBackListenerArgumentCaptor.getValue().onSuccess(ArgumentMatchers.<Example>anyList());

    InOrder inOrder = Mockito.inOrder(view);
    inOrder.verify(view).showProgressBar(true);
    inOrder.verify(view).showProgressBar(false);
    inOrder.verify(view).showImageList(ArgumentMatchers.<Example>anyList());

}

// Negative test
@Test
public void getImageListNetworkError() {

    when(networkStatus.isOnline()).thenReturn(false);

    presenter.getImageList(networkStatus);

    verify(repository).getList(networkStatusArgumentCaptor.capture(), callBackListenerArgumentCaptor.capture());
    callBackListenerArgumentCaptor.getValue().onError(anyString());

    InOrder inOrder = Mockito.inOrder(view);
    inOrder.verify(view).showProgressBar(true);
    inOrder.verify(view).showProgressBar(false);
    inOrder.verify(view).showError(anyString());

}

}

Test cases for Repository class

package com.ram.com.mvp_sample;

import com.ram.com.mvp_sample.modal.DataSource;
import com.ram.com.mvp_sample.modal.RemoteRepository;
import com.ram.com.mvp_sample.modal.Repository;
import com.ram.com.mvp_sample.modal.pojo.Example;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class RepositoryTest {

    private Repository repository;

    @Mock
    private RemoteRepository remoteRepository;

    @Mock
    private NetworkStatus networkStatus;

    @Captor
    private ArgumentCaptor<NetworkStatus> networkStatusArgumentCaptor;

    @Mock
    private DataSource.OnResponseCallBackListener callBackListener;
    @Captor
    private ArgumentCaptor<DataSource.OnResponseCallBackListener> callBackListenerArgumentCaptor;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        repository = Repository.getInstance(remoteRepository);
    }

    @Test
    public void getImageList() {

        when(networkStatus.isOnline()).thenReturn(true);

        repository.getList(networkStatus, callBackListener);
        verify(remoteRepository).getList(networkStatusArgumentCaptor.capture(), callBackListenerArgumentCaptor.capture());
        callBackListenerArgumentCaptor.getValue().onSuccess(ArgumentMatchers.<Example>anyList());
        Mockito.verify(callBackListener).onSuccess(ArgumentMatchers.<Example>anyList());

        callBackListenerArgumentCaptor.getValue().onError("Some Error");
        Mockito.verify(callBackListener).onError("Some Error");

    }

}

Let me know if you have any doubts

I have been using Mockito for writing unit test cases for components which are not completely independant.

to start using mockito add following dependancies in your project

    // required if you want to use Mockito for unit tests
    testCompile 'org.mockito:mockito-core:2.7.22'
    // required if you want to use Mockito for Android tests
    androidTestCompile 'org.mockito:mockito-android:2.7.22'

Unit tests work on a single thread and api call happens on some differant thread. So you will need to mock the response from server. For that you can use mockito.

So typically in api calls all you need to check is if response from server is getting parsed into your pojo. But getting server response in unit test is not possible. Hence you'll need to mock the response. For that mocking use Mockito.

Related