Android – unit testing using mockito for transformation API call – argumentcaptor
Please forgive me if my question looks repetitive, but I don't get how to test and transform API calls. Build.gradle at the application level
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile("com.android.support.test.espresso:espresso-core:$rootProject.ext.expressoVersion", {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile "com.android.support:appcompat-v7:$rootProject.ext.supportLibraryVersion"
compile "com.jakewharton:butterknife:$rootProject.ext.butterKnifeVersion"
annotationProcessor "com.jakewharton:butterknife-compiler:$rootProject.ext.butterKnifeVersion"
// Dependencies for local unit tests
testCompile "junit:junit:$rootProject.ext.junitVersion"
testCompile "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
testCompile "org.hamcrest:hamcrest-all:$rootProject.ext.hamcrestVersion"
testCompile "org.powermock:powermock-module-junit4:$rootProject.ext.powermockito"
testCompile "org.powermock:powermock-api-mockito:$rootProject.ext.powermockito"
compile "com.android.support.test.espresso:espresso-idling-resource:$rootProject.ext.espressoVersion"
// retrofit, gson
compile "com.google.code.gson:gson:$rootProject.ext.gsonVersion"
compile "com.squareup.retrofit2:retrofit:$rootProject.ext.retrofitVersion"
compile "com.squareup.retrofit2:converter-gson:$rootProject.ext.retrofitVersion"
}
The project level build. Gradle has this extra content
//Define versions in one place
ext {
// Sdk and tools
minSdkVersion = 15
targetSdkVersion = 25
compileSdkVersion = 25
buildToolsVersion = '25.0.2'
supportLibraryVersion = '23.4.0'
junitVersion = '4.12'
mockitoVersion = '1.10.19'
powermockito = '1.6.2'
hamcrestVersion = '1.3'
runnerVersion = '0.5'
rulesVersion = '0.5'
espressoVersion = '2.2.2'
gsonVersion = '2.6.2'
retrofitVersion = '2.0.2'
butterKnifeVersion = '8.5.1'
expressoVersion = '2.2.2'
}
Main activities
public class MainActivity extends AppCompatActivity implements MainView {
@BindView(R.id.textViewApiData)
TextView mTextViewApiData;
@BindView(R.id.progressBarLoading)
ProgressBar mProgressBarLoading;
private MainPresenter mMainPresenter;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initializeComponents();
}
private void initializeComponents() {
mMainPresenter = new MainPresenter(this);
mMainPresenter.presentDataFromApi();
}
@Override
public void onResponseReceived(final String response) {
mTextViewApiData.setText(response);
}
@Override
public void one rrorReceived(final String message) {
mTextViewApiData.setText(message);
}
@Override
public void showProgressDialog(final boolean enableProgressDialog) {
mProgressBarLoading.setVisibility(enableProgressDialog ? View.VISIBLE : View.GONE);
}
}
Mainview for
public interface MainView {
void onResponseReceived(String response);
void one rrorReceived(String message);
void showProgressDialog(boolean enableProgressDialog);
}
ApiClient
public class ApiClient {
private static Retrofit sRetrofit;
public static Retrofit getInstance() {
if (sRetrofit == null) {
sRetrofit = new Retrofit.Builder()
.baseUrl(Constants.Urls.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return sRetrofit;
}
}
host
public class MainPresenter {
private final MainView mMainView;
private final Call<List<UserResponse>> mCallListUserResponse;
public MainPresenter(final MainView mainView) {
this.mMainView = mainView;
final ApiInterface apiInterface = ApiClient.getInstance().create(ApiInterface.class);
mCallListUserResponse = apiInterface.getUsers();
}
public void presentDataFromApi() {
mMainView.showProgressDialog(true);
mCallListUserResponse.enqueue(new Callback<List<UserResponse>>() {
@Override
public void onResponse(final Call<List<UserResponse>> call,
final Response<List<UserResponse>> response) {
mMainView.onResponseReceived(Constants.DummyData.SUCCESS);
mMainView.showProgressDialog(false);
}
@Override
public void onFailure(final Call<List<UserResponse>> call, final Throwable t) {
mMainView.onErrorReceived(Constants.DummyData.ERROR);
mMainView.showProgressDialog(false);
}
});
}
}
ApiInterface
public interface ApiInterface {
@GET(Constants.Urls.USERS)
Call<List<UserResponse>> getUsers();
}
constant
public class Constants {
public class Urls {
public static final String BASE_URL = "https://jsonplaceholder.typicode.com";
public static final String USERS = "/users";
}
}
This is what I want to do, but it doesn't work. The test case will now pass because I commented on 3 lines in the last line. After uncommenting these lines, you can see the errors. Test case
public class MainPresenterTest {
@InjectMocks
private MainPresenter mMainPresenter;
@Mock
private MainView mMockMainView;
@Mock
private Call<List<UserResponse>> mUserResponseCall;
@Captor
private ArgumentCaptor<Callback<List<UserResponse>>> mArgumentCaptorUserResponse;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void presentDataFromApitest() throws Exception {
mMainPresenter.presentDataFromApi();
verify(mMockMainView).showProgressDialog(true);
// verify(mUserResponseCall).enqueue(mArgumentCaptorUserResponse.capture());
// verify(mMockMainView).onResponseReceived(Constants.DummyData.SUCCESS);
// verify(mMockMainView).showProgressDialog(false);
}
}
journal
Wanted but not invoked:
mUserResponseCall.enqueue(
<Capturing argument>
);
-> at com.example.ranaranvijaysingh.testingdemo.presenters.MainPresenterTest.presentDataFromApiTest(MainPresenterTest.java:69)
Actually, there were zero interactions with this mock.
resolvent:
Your code looks syntactically correct. However, I suspect @ injectmock cannot inject mock objects into the final instance variables. When you call mmainpresenter. Presentdatafromapi(), the following variables may be used as instances:
private final Call<List<UserResponse>> mCallListUserResponse;
You should try to manually inject the mock variable into this class and assign it to the mcalllistuserresponse so that it can be obtained from the mockito instance
It may be worth trying the following steps:
>Set the variable mcalllistuserresponse in the mainpresenter to non final. > add a method in the mainpresenter class, as shown below:
Void setuserresponsecall (call > userresponse) {mcalllistuserresponse = userresponse;} > now do the following in the test class:
Modify your test as follows
@Test
public void presentDataFromApitest() throws Exception {
//Set mock instance of the user response
mMainPresenter.setUserResponseCall(mUserResponseCall);
//real object call to presentDataFromApi();
mMainPresenter.presentDataFromApi();
verify(mMockMainView).showProgressDialog(true);
verify(mUserResponseCall).enqueue(mArgumentCaptorUserResponse.capture());
}
I hope I can help you