Reputation: 7066
In my MainActivity
I have a method called getAPI
that returns an OTBServiceWrapper
. This is used to setup retrofit for calling to an API.
In my MainActivityTest
file I am trying to stub out the new OTBService().getService()
call that the getApi
method is making so I can return a MockedOTBService
which changes the client to a custom one that return json
.
As is, the current implementation will it the MockedOTBService
if I had to place a logger within MockedOTBService
but also falls through and calls the real api, which is not want I want in a test.
I am trying to stub the Retrofit API calls using Mockito and return json
. I cant seem to understand why the stub is being called yet is not stubbing the method in question.
Notes:
ActivityInstrumentationTestCase2
verify(mockedOTBService, atLeastOnce()).getService();
is says it was never called.when...thenReturn
to use a mMainActivity = spy(getActivity())
there is not change and the real API is called.Logcat Output
Logger﹕ MockedOTBService was called // Mock is called
Logger﹕ Real OTBService was called // Real API is called
Logger﹕ MainActivity getAPI method class is "$Proxy1" // Mock is shown in MainActivity
Logger﹕ RealAPIResponse JSON Parsed ID: 266 // Real API response returned
Real Flow
MainActivity.onCreate() > OTBService.getService() > OTBServiceWrapper.createSearch(...)
Trying to Achieve within Tests
MainActivity.onCreate() > MockedOTBService.getService() > OTBServiceWrapper.createSearch(...)
MainActivity.java
public class MainActivity extends Activity {
private OTBServiceWrapper serviceWrapper;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getApi().createSearch(...)
}
public OTBServiceWrapper getApi() {
return new OTBService().getService();
}
}
OTBService.java
public class OTBService {
public OTBServiceWrapper getService() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(Constants.API_URL)
.build();
return restAdapter.create(OTBServiceWrapper.class);
}
}
OTBServiceWrapper.java
public interface OTBServiceWrapper {
@POST(Constants.API_SEARCHES_POST_URL)
void createSearch(@Body Request request, Callback<Request.Response> callback);
}
MainActivityTest.java
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
private OTBService mMockedOTBService;
private MainActivity mMainActivity;
private View mSearchButton;
public MainActivityTest() { super(MainActivity.class); }
@Override
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(true);
System.setProperty("dexmaker.dexcache", getInstrumentation().getTargetContext().getCacheDir().getPath());
mMockedOTBService = mock(OTBService.class);
when(mMockedOTBService.getService()).thenReturn(new MockedOTBService(getInstrumentation().getContext()).getService());
mMainActivity = getActivity();
mSearchButton = mMainActivity.findViewById(R.id.AbSearchButton);
mYourHolidayButton = mMainActivity.findViewById(R.id.AbYourHolidayButton);
}
public void testButtonActions() {
TouchUtils.clickView(this, mSearchButton);
...
}
}
MockedOTBService.java
public class MockedOTBService {
private Context context;
public MockedOTBService(Context context) { this.context = context; }
public OTBServiceWrapper getService() {
RestAdapter restAdapter;
restAdapter = new RestAdapter.Builder()
.setClient(new LocalJsonClient(context))
.setEndpoint(Constants.API_TEST_URL)
.build();
return restAdapter.create(OTBServiceWrapper.class);
}
}
LocalJsonClient.java
@SuppressLint("DefaultLocale")
public class LocalJsonClient implements Client { ... }
build.gradle
dependencies {
androidTestCompile 'com.google.dexmaker:dexmaker:1.0'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0'
}
Upvotes: 8
Views: 1711
Reputation: 2429
Remove the need for mocking your request by allowing the Activity to set the service.
In your MainActivity
create a class variable and a class setter for the service. It needs to be a at the class scope to prevent the OnCreate
method being called before you have set the service to what you want it to be. Also create an instance getter which sets the service if you have not already.
In your test before you call getActivity()
set the service to be your mock service. (Maybe think about moving this out to a support object).
MainActivity.java
public class MainActivity extends Activity {
private static OTBServiceWrapper serviceWrapper;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getServiceWrapper.createSearch(...)
}
public OTBServiceWrapper getServiceWrapper() {
if (serviceWrapper == null) {
MainActivity.setServiceWrapper(new OTBService().getService());
}
return serviceWrapper;
}
public static void setServiceWrapper(OTBServiceWrapper serviceWrapper) {
MainActivity.serviceWrapper = serviceWrapper;
}
}
MainActivityTest.java
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
private MainActivity mMainActivity;
public MainActivityTest() { super(MainActivity.class); }
@Override
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(true);
MainActivity.setServiceWrapper(
new MockedOTBService(getInstrumentation().getContext()).getService()
);
mMainActivity = getActivity();
}
}
Upvotes: 6