Mockito Error -"there were zero interactions with this mock" - android

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
// Send SiteCatalyst data
//create trigger to adobe analytics when the view visible
mMeasurement = MeasurementWrapper.create(MeasurementEnum.SPLASH);
mMeasurement.trackSplashState();
here I called trackSplashState inside onCreate method in Splash screen.
#Override
public void trackSplashState() {
HashMap<String, Object> data = createCommonData();
MeasureServiceImpl.StartStatus status = mMeasureService.getLaunchStatus();
switch (status) {
case INSTALL: {
data.put("appevent.install", "install");
break;
}
case LAUNCH: {
data.put("appevent.launch", "launch");
break;
}
case UPDATE: {
data.put("appevent.update", "update");
break;
}
}
mAnalyticsService.trackState(mType, data);
}
Method functionality inside MeassurementWrapper.java class
#Override
public void trackState(MeasurementEnum mType, HashMap<String, Object> data, String... additionalData) {
try {
String stateName = MeasurementWrapper.DEVICE_NAME + ":" + String.format(mType.getName(), additionalData);
// Check last Adobe Analytic page value is same to the current page value if so avoiding it send to the Adobe analytics tracking
if (!isPageAndUrlMatching(mType,data)) {
Analytics.trackState(stateName, data);
}
} catch (MissingFormatArgumentException e) {
Log.e(this.getClass().getName(), e.getMessage());
}
}
Implementation of the trackState method inside service(AnalyticsServiceImpl).
<-------- Test Class -------------->
#Config(constants = BuildConfig.class, sdk = TestConfig.SDK)
#RunWith(RobolectricTestRunner.class)
public class AdobeAnalyticsTriggerTest {
private ArgumentCaptor<MeasurementEnum> enumArgumentCaptor;
#Module(includes = TestAppModule.class, injects = AdobeAnalyticsTriggerTest.class, overrides = true)
static class TestModule {}
#Inject
Context context;
#Captor
ArgumentCaptor<HashMap<String, Object>> data;
#Captor
ArgumentCaptor<String[]> varargs;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Services.initialize(new AdobeAnalyticsTriggerTest.TestModule()).inject(this);
enumArgumentCaptor = ArgumentCaptor.forClass(MeasurementEnum.class);
}
#After
public void tearDown() throws Exception {
}
#Test
public void shouldTrackSplashscreen_afterOnCreate(){
SplashActivity splashActivity = Robolectric.buildActivity(SplashActivity.class).create().get();
Measurement measurement = mock(splashActivity.mMeasurement);
verify(((MeasurementWrapper) measurement).mAnalyticsService, times(1)).trackState(enumArgumentCaptor.capture(), data.capture());
}
/**
* Mocks measurement (so stuff is not sent to sitecatalyst)
* #return measurement
*/
private Measurement mock(Measurement measurement) {
MeasurementWrapper wrapper = (MeasurementWrapper) measurement;
wrapper.mAnalyticsService = Mockito.spy(new AnalyticsServiceImpl());
// overwrite sendTrackAction() to prevent logs being sent somewhere
doAnswer(invocationOnMock -> null).when(wrapper.mAnalyticsService).trackAction(any(MeasurementEnum.class), (HashMap) anyMapOf(String.class, Objects.class));
// overwrite sendStateAction() to prevent logs being sent somewhere
doAnswer(invocationOnMock -> null).when(wrapper.mAnalyticsService).trackState(any(MeasurementEnum.class), (HashMap) anyMapOf(String.class, Objects.class));
return wrapper;
}
I need to test(shouldTrackSplashscreen_afterOnCreate) trackState method of the AnalyticsServiceImpl calling when splash screen call onCreate method. But the issue is that I always get an error from Mockito that Actually, there were zero interactions with this mock.Can someone help me to fix this issue. It will be a big help for me. Thanks and regards.

You need to add you're test code between the mocking and the verification part, example see below.
Currently there is no method call done on the mock, hence you get the error message from mockito.
#Test
public void shouldTrackSplashscreen_afterOnCreate(){
SplashActivity splashActivity = Robolectric.buildActivity(SplashActivity.class).create().get();
Measurement measurement = mock(splashActivity.mMeasurement);
// ... add test code here ...
verify(((MeasurementWrapper) measurement).mAnalyticsService, times(1)).trackState(enumArgumentCaptor.capture(), data.capture());
}

Related

Method skips a synchronous operation working asynchronously

Using Retrofit to check values in database for a login operation. I don't want to move forward without checking this thus want this to occur synchronically.
I am using the execute method instead of enqueue but still getting the result asynchronously. I understand if I do it all in the same class, it might work but I am trying to keep things separately to prevent code duplicate for other future calls. Please advice what I am doing wrong or how I could go about addressing this. Thanks.
Following method occurs when I click a submit button. This method is at my Activity.
Note that everything in this method works. Problem is after startService, it doesn't wait to get information from my rest service and instead jumps straight to the Toast. After that it carries on to perform the execute method which is useless by then.
private void sendLoginRequest(User user){
String token = verificationHelper.createToken(properties.API_KEY, user, 60000);
Retrofit retrofit = retrofitHelper.getRetrofit(properties.BASE_URL);
UserRepository userRepository = retrofit.create(UserRepository.class);
Call<User> call = userRepository.login(token);
if(call != null){
syncService = new SyncService(call);
Intent i = new Intent(this, SyncService.class);
startService(i);
if(verificationHelper.isValidLogin()){
goToMainActivity();
}
}
Toast.makeText(this, "Invalid Login", Toast.LENGTH_SHORT).show();
}
This is my service which gets into the onHandleIntent method after the Toast is called. (Expecting this to be called first and validated before ever going to the Toast).
public class SyncService extends IntentService {
private VerificationHelper verificationHelper = new VerificationHelper();
private PropertiesUtil properties = new PropertiesUtil();
private RetrofitHelper retrofitHelper = new RetrofitHelper(verificationHelper, properties);
private static Call<User> staticCall;
public SyncService(Call<User> call) {
super("SyncService");
staticCall = call;
}
public SyncService(){
super("SyncService");
}
#Override
protected void onHandleIntent(Intent intent) {
retrofitHelper.performCallBackSync(staticCall);
}
}
This is over at my RetrofitHelper for reference.
public class RetrofitHelper {
private VerificationHelper verificationHelper;
private PropertiesUtil properties;
public RetrofitHelper(VerificationHelper verificationHelper, PropertiesUtil properties) {
this.verificationHelper = verificationHelper;
this.properties = properties;
}
public void performCallBackSync(Call<User> call){
try {
// some logic that handles and verifies token values.
verificationHelper.setValidLogin(true);
} catch (IOException e) {
//some error handling
}
}
}

How to test element of custom sdk android unit test

I've started learning android unit tests, but it looks very hard to find some good guides or information. Every example have a stupid example about 2+2 = 4
Say I write a little SDK which has few functions
MySdk.Init(Context context)
MySdk.CallTask()
I create an androidTest file
How should I call my SDK functions to check how they work? Somewhere required parameters like int/string/context. I just really don't understand, please help me.
This is what I've tried
public class AndroidTest {
private Activity context;
//default test
#Test
public void addition_correct() throws Exception {
assertEquals(4, 2 + 2);
}
#Test
public void checkContext() {
context = getActivity();
assertNotNull(context);
}
#Test
public void testInitPhase() {
MySdk.Init(context, new SdkInitializationListener() {
#Override
public void onInitializationSuccessful(String adv_id) {
assert (adv_id != null);
}
#Override
public void onInitializationError() {
}
});
}
}
For context i was tried context = new mockContext();. It's passed as context = null and my SDK failed with initialization.
Unit tests are mainly about testing an individual class in isolation, so that you can check if individual public methods of a class behave as you intend them to, and continue to do so if you change that class' code in the future. Let's say you have a class like this:
public class UtilityFunctions {
public int double(int value) {
return value * 2;
}
public String mirror(String value) {
if (value == null) return "";
return value + new StringBuilder(value).reverse().toString();
}
}
You want to test these two methods with:
valid input values, and check the output is as expected
invalid values, and check that errors are handled accordingly (and the correct exceptions thrown if necessary)
So a test class for the above class may look like this
#RunWith(JUnit4.class)
public class UtilityFunctionsTest {
private UtilityFunctions utility;
#Before
public void setUp() {
// Initialises any conditions before each test
utility = new UtilityFunctions();
}
#Test
public void testDoubleFunction() {
assertEquals(2, utility.double(1));
assertEquals(8, utility.double(4));
assertEquals(-12, utility.double(-6));
assertEquals(0, utility.double(0));
}
#Test
public void testMirror() {
assertEquals("", utility.mirror(null));
assertEquals("", utility.mirror(""));
assertEquals("aa", utility.mirror("a"));
assertEquals("MirrorrorriM", utility.mirror("Mirror"));
}
}
These standard Java unit tests are run from the test directory. However, you'll need to run tests in the androidTest directory whenever you're using Android-specific classes such as Context. If you're creating a MockContext, you're simply creating an empty Context whose methods don't do anything.
Without me knowing anything about what your MySDK does, I think you may need to pass a fully-functioning Context into your class for your tests. The Android JUnit runner does provide this with InstrumentationRegistry.getTargetContext(), so for your example, you may need to add this #Before method:
#Before
public void setUp() {
context = InstrumentationRegistry.getTargetContext();
}
You'll also need to remove the context = getActivity(); line from your first test.

how to test private Observable inside public method?

I am new with tests.
I have something like next code and wish to cover it with unitTests using the Mockito:
public void doSomeJob(){
//some code before
getMvpView().execute(getObservable());
//some code after
}
private Observable<Boolean> getObservable(){
return Observable.create(new ObservableOnSubscribe<Boolean>() {
#Override
public void subscribe(#NonNull ObservableEmitter<Boolean> e) throws Exception {
Thread.sleep(5000);
e.onNext(true);
e.onComplete();
}
});
}
so questions:
how correct write test for getMvpView().execute(getObservable()); using Mokito?
how can i verify result of getObservable()?
If your private method is not a part of the interface, i.e. cannot be reached from outside the class, it's not something you should test (presumably it's not, since it's private). Mockito in turn doesn't provide mocking of private methods. Thereby you either need to change your interface (make this data available outside) or leave it without testing.
What you should test is the effect of calling the public methods of your class under test. If you do so you will be able to freely refactor the implementation details later, and your tests will still verify that your class works as expected.
I suppose that your code is part of a presenter implementation and the getMvpView() method returns a view interface:
public class MvpPresenterImpl {
private MvpView view;
public void doSomeJob(){
//some code before
getMvpView().execute(getObservable());
//some code after
}
public void attachView(MvpView view) {
this.view = view;
}
private MvpView getMvpView() {
return view;
}
private Observable<Boolean> getObservable(){
return Observable.create(new ObservableOnSubscribe<Boolean>() {
#Override
public void subscribe(#NonNull ObservableEmitter<Boolean> e) throws Exception {
Thread.sleep(5000);
e.onNext(true);
e.onComplete();
}
});
}
}
You can test the effect of doSomeJob() like so:
public class MvpPresenterImplTest {
private MvpPresenterImpl presenter;
private MvpView mockView;
#Before
public void setUp() throws Exception {
// Create a mock view instance so that we can verify method calls on it
mockView = mock(MvpView.class);
// Create our object under test, and set it up with the mock view
presenter = new MvpPresenterImpl();
presenter.attachView(mockView);
}
#Test
public void doSomeJob_callsExecuteOnViewWithCorrectObserver() throws Exception {
// What we want to test is the effect of invoking a public method.
presenter.doSomeJob();
// Verify that the execute method has been called by your class
// under test, and save the parameter for later.
ArgumentCaptor<Observable<Boolean>> paramCaptor =
ArgumentCaptor.<Observable<Boolean>>forClass((Class)Observable.class);
verify(mockView).execute(paramCaptor.capture());
// Get the actual observable that the execute method was called with.
Observable<Boolean> param = paramCaptor.getValue();
// Get a test observer so that we can check what our Observable emits
// (TestObserver is a built-in feature of RxJava, not Mockito.)
TestObserver<Boolean> test = param.test();
// Assert that the Observable behaves as expected
test.assertComplete();
test.assertResult(true);
}
}

How to unit test methods posted by Event Bus in android?

I am using Otto's event bus in my application. In one of my classes I am posting the event.
MyEvent myevent = new MyEvent();
uiBus.post(myEvent);
I am able to test the post method.
Now there is another class which is receiving the event.
//ReceiverClass.java
#Subscribe
public void onEventReceived(MyEvent myevent) {
callAMethod();
}
How do I unit test that this method was invoked. I tried with the following test code
#Mock
Bus uiBus;
#Test
public void testBusReceviedEvent() {
ReceiverClass instance = new ReceiverClass();
mockBus.register(instance);
MyEvent myevent = new MyEvent();
mockBus.post(myEvent);
//Test
verify(instance, times(1)).callAMethod();
}
But this code doesn't work.
I'm a little late to the party but here is an example of a class which works and accounts for async calls. Instead of Mocking EventBus we simply let it do it's thing and register it in the TestDriver class below.
The thing that makes this work is the CountDownLatch which, with the help of the abstract DataTransferCallback class, waits for latch.countDown() to be called or 5 seconds to go by.
Just register your test class and in the #Subscribe method, pass it back to the method that created the DataTransferCallback and do your assertions there.
#RunWith(AndroidJUnit4.class)
public class TestDriver {
private final CountDownLatch latch = new CountDownLatch(1);
private EventBus eventBus;
private DataTransferCallback transferCallback;
public abstract class DataTransferCallback {
abstract void onSuccess(DataTransfer event);
}
#Before
public void setUp() {
EventBus.getDefault().register(this);
eventBus = spy(EventBus.getDefault());
}
#SuppressWarnings("unchecked")
#Test
public void test200Resposne() throws InterruptedException {
// Get known good JSON
final String json = TestJSON.get200Response();
// Class under test
final Driver driver = new Driver(InstrumentationRegistry.getTargetContext());
final JsonParser jsonParser = new JsonParser();
//boolean to hold our test result
final boolean[] testPassed = new boolean[]{false};
transferCallback = new DataTransferCallback() {
#Override
public void onSuccess(DataTransfer event) {
assertNotNull(event);
verify(eventBus).post(event);
assertThat(event.getStatus(), is("OK"));
assertTrue(event.getData() != null);
testPassed[0] = true;
}
};
//Set our test EventBus object
driver.setEventBus(eventBus);
// The actual method under test
driver.parseData(jsonParser.parse(json));
// Set a countdown latch to wait for the result (5s)
latch.await(5000, TimeUnit.MILLISECONDS);
// will wait here until 5s or the #Subscrube method is hit
assertTrue(testPassed[0]);
}
//Because we want to examine EventBus Output, register it
//to this class and pass the event back through our custom abstract class
#Subscribe
public void onReceiveEventBusEvent(DataTransfer event) {
assertNotNull(transferCallback);
transferCallback.onSuccess(event);
//notify latch so that we can proceed
latch.countDown();
}
}
It does not work because instance is not a mock. You will have to verify the effects of callAMethod or put that method in another class and inject a mock of this new class into your ReceiverClass class.
For example...
private class ReceiverClass {
private MyNewClass theNewClassIWasTalkingAbout;
// Stick in a setter for that ^
#Subscribe
public void onEventReceived(MyEvent myevent) {
theNewClassIWasTalkingAbout.callAMethod();
}
}
Then your test will have to change slightly...
#Mock
private MyNewClass mockNewClass;
#InjectMocks // This will be the "solid" implementation of the thing you are trying to test, it is not a mock...
private ReceiverClass instance;
#Test
public void testBusReceivedEvent() {
mockBus.register(instance);
MyEvent myevent = new MyEvent();
mockBus.post(myevent);
verify(mockNewClass, times(1)).callAMethod();
}
Hope this helps.

Mockito - right way to test a method with params

I need your assistance please:
I have this method:
public class MyTestClass {
protected void foo(JSONObject result, String text){
String userId = result.optString("name");
mApi.sendInfo(userId, text, mListener);
}
}
In Mockito I do:
#Test
public void whenFooIsCalledThenSendInfoGetsCalled(){
MyTestClass testClassSpy = spy(mMyTestClass);
JSONObject jsonOb = mock(JSONObject.class);
when(jsonOb.optString("name")).thenReturn("something");
testClassSpy.foo(eq(jsonOb), anyString());
....
some verification....
The problem is, the when the foo method gets called, JSONObject result is null.
I can't seem to get this to work. I thought that if I mock the object and make it return a String once optString("name") is called, would solve this issue but it seems NPE is all I get.
What am I doing wrong?
Thanks you
I am not from Java world but when I look on this code snippet I'm not sure what you want to test. If you want to verify exactly what your test method suggest whenFooIsCalledThenSendInfoGetsCalled then:
You should create spy for mApi
You should create stub for JSONObject result
You should use real implementation of MyTestClass
So your SUT class should allow for injecting dependencies:
public class MyTestClass {
private mApi;
public MyTestClass(Api api) {
mApi = api;
}
void foo(JSONObject result, String text){ /* your implementation */}
}
And your test method:
#Test
public void whenFooIsCalledThenSendInfoGetsCalled(){
// arrange test
Api spyApi = spy(Api.class);
JSONObjec stub = mock(JSONObject.class);
when(stub.optString("name")).thenReturn("something");
MyTestClass sut = new MyTestClass(spyApi);
// Act
sut.foo(stub, "text");
// Assert
verify(spyApi , times(1)).foo(eq("something"), "text", listener);
}

Categories

Resources