How to mock the same method multiple times use mockito - android

I have a method that needs to be called multiple times, and I can return the same result in the test case, I invoke when use for loop, but is there more simple way to do this?
val ONE_DAY_FORMAT: SimpleDateFormat = SimpleDateFormat("yyyy-MM-dd")
val tempCalendar = Calendar.getInstance()
for (i in (0..15)) {
`when`(accountingDao.sumOfDay(ONE_DAY_FORMAT.format(tempCalendar.time)))
.thenReturn(100.0f)
tempCalendar.add(Calendar.DAY_OF_YEAR, -1)
}

Normally when the set-up is more complicated, the doAnswer strategy would be used:
Mockito.doAnswer(new Answer<Float>() {
#Override
public Float answer(InvocationOnMock invocation) throws Throwable {
String argument = (String)invocation.getArgument(0);
if(supportedDates.contains(argument)){
return 100.00f;
}else{
return null;
}
}
}).when(accountingDao.sumOfDay(any(String.class)));
So you basically catch the input param and then decide based on its value what should be returned dynamically.

Instead of mocking the same method, mock the method once and call the verify method by passing the optional Verification mode parameter. For example if you want that some method of your mocked class get called twice, you can make a verify statement like this
verify(mockedClass, Mockito.times(2)).someMethod();
This will test if someMethod() is getting called twice.

Move your "when ..." statement out of your loop:
when`(accountingDao.sumOfDay(any()).thenReturn(100.0f)

Related

Android MVVM: databinding value is not set from MediatorLiveData in particular situation

When setting a value to MediatorLiveData that reacts to a source added in the constructor of a viewModel or activity onCreate observer in the ViewModel , like this for example:
showingMethodLiveData.addSource(stateChangeLiveData) {
when (it) {
ConfigurationState.CURRENT -> showingMethodLiveData.value = commMethod[it]
ConfigurationState.PENDING -> showingMethodLiveData.value = commMethod[it]
}
}
The value isn't set to the observing view, although the set method is called.
I can work around this by either adding the source in onStart (which creates other problems of registering observer more than once), or using postValue instead of setValue.
The debug of setValue method leads me to following code, where there is an interesting comment that tells the story, the method returns without setting the value to the binded view.
in androidx.databinding package of lifecycle dependency:
class ViewDataBinding:
private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
if (mInLiveDataRegisterObserver) {
// We're in LiveData registration, which always results in a field change
// that we can ignore. The value will be read immediately after anyway, so
// there is no need to be dirty.
return;
}
boolean result = onFieldChange(mLocalFieldId, object, fieldId);
if (result) {
requestRebind();
}
}
The value is not set afterwards either, but only when the mediatorlivedata is invoked again by change in it's source.
Why this situation occurs?
Thank you for the help
PS
I think it may be an android library bug
The use of Mediatorlivedata is to compare two values and then provide a result.
If you want to change the value of a variable, you can simply use MutableLiveData and to assign a new value, write variableName.value = newValue
Should be even easier to achieve like this:
val showingMethodLiveData = Transformations.map(stateChangeLiveData) { commMethod[it] }

How to test presenter method that create a new object inside it?

I have this method to validate Unit. I send field values and inside it method I create a new model and then return that model via interface.
public void validate(String unitNumber, Integer unitTypeId, String notes) {
if(!TextUtils.isEmpty(unitNumber)) {
Unit unit = new Unit();
unit.setUnitNumber(unitNumber);
unit.setFlatTypeId(unitTypeId);
unit.setNotes(notes);
view.displayUnitValid(unit);
} else {
view.displayUnitNotValid();
}
}
Now I want do do unit testing of this method with the following code.
#Test public void shouldValidateSinceUnitNumberIsValid() {
// Given
String unitNumber = "1";
// When
presenter.validate(unitNumber, null, null);
// Then
Mockito.verify(view).displayUnitValid(new Unit());
}
I am getting the following error message:
Argument(s) are different! Wanted:
view.displayUnitValid(
com.rwar.domain.customers.Unit#57cf54e1
);
-> at com.rwar.presentation.work_orders.AddUnitPresenterTest.shouldValidateSinceUnitNumberIsValid(AddUnitPresenterTest.java:73)
Obvisouly there is a problem since I am creating a new Unit instance here:
Mockito.verify(view).displayUnitValid(new Unit());
And inside validate() method I create another instance of Unit.
How I can fix this?
Pass the same arguments to your verifying method, e.g.
Unit expected = new Unit()
unit.setUnitNumber(unitNumber);
unit.setFlatTypeId(unitTypeId);
unit.setNotes(notes);
Mockito.verify(view).displayUnitValid(expected);
You'll likely have to override your Unit classes equals/hashcode method such that they compare their contents and not the instance itself.
Here is the working solution that might be useful to someone else:
#Test public void shouldValidateSinceUnitNumberIsValid() {
// Given
String unitNumber = "1";
// When
presenter.validate(unitNumber, null, null);
// Then use ArgumentCaptor to get unit value from newly created object inside validate() method
ArgumentCaptor<Unit> argument = ArgumentCaptor.forClass(Unit.class);
Mockito.verify(view).displayUnitValid(argument.capture());
// Compare captured argument of Unit number with local unitNumber
assertEquals(argument.getValue().getUnitNumber(), unitNumber);
}
In case you want to do this in Kotlin, you can use Mockito check function to make asserts over the Unit instance that is passed as an argument of displayUnitValid(). Something like this:
Mockito.verify(view).displayUnitValid(Mockito.check { unit ->
assertEquals(unitNumber, unit.getUnitNumber)
});
More info about check here

RxJava2 changing type of Flowable object being returned by API

The DarkSkyAPI call returns Forecast object containing WeeklyData object that in turn contains Array<DailyData>.
My Repository class requires Array<DailyData> to cache and propagate the data to the Presenter.
Currently I am calling the API like this:
Flowable<Forecast> response = service.getRxWeatherResponse(params...);.
How can I unwrap this Flowable<Forecast> to extract Flowable<Array<DailyData>> to be returned to the Repository class?
Thank you.
Got it Chris, thanks! I've used the map operator as you advised. Final code returns Observable and looks like this:
return service.getRxWeatherResponse(API cal params...)
.map(new Function<Forecast, List<DailyData>>() {
#Override
public List<DailyData> apply(Forecast forecast) throws Exception {
return forecast.getWeeklyData().getDailyData();
}
});
Or simplified using lambda:
return service.getRxWeatherResponse(API cal params...)
.map(forecast -> forecast.getWeeklyData().getDailyDataArray());

Using zip() with a Maybe that may not emit a value

I'm trying to execute two Maybe at once and call a specific method once both are done. This works if both Observables return a value but in certain cases one might not emit an item thus calling only doOnComplete and not doOnSuccess. So if one of those Maybes' doesn't call doOnSuccess the zip() block isn't executed. I'm wondering how to handle such a scenario?
Following my code (stripped down to the essential part):
private void fetchData(){
Maybe<Integer> maybeOne = getId(); // may return Maybe.empty()
Maybe<List<String>> maybeTwo = getList();
Maybe.zip(maybeOne, maybeTwo, (id, list) -> {
initView(id, list); // only called if values have been emitted
return true;
}).subscribe();
}
I would expect that the zip() block is always called but with null values in case the Maybe didn't call onSuccess. This isn't the case so can I handle such a scenario?
You can use the materialize operator. It basically transforms the serial invocation into object (wrapped inside a Notification object).
Observable.zip(maybeOne.toObservable().materialize(),
maybeTwo.toObservable().materialize(), (id, list) -> {
Log.d(TAG, "zip completed");
return true;
}).subscribe();
Now your zip will always "finish", but your real data can be retrieved using:
id.getValue()
And if your maybe is Maybe.empty() then it will not return the value, but null.

Passing parameter to Observable.create

I am using RXJava on Android for asynchronously access the database.
I want to save an object in my database.
In this way, I created a method which take a final parameter (the object I want to save) and returns an Observable.
At this point I don't care to emit anything so I will call subscriber.onComplete() at the end.
Here is my code:
public Observable saveEventLog(#NonNull final EventLog eventLog) {
return Observable.create(new Observable.OnSubscribe<Object>() {
#Override
public void call(Subscriber<? super Object> subscriber) {
DBEventLog log = new DBEventLog(eventLog);
log.save();
subscriber.onCompleted();
}
});
}
The thing is, I saw many answer using the final keyword for the parameter, but I would like to do this without it.
The reason is I don't really like the approach of declare a final variable in order to use it in another thread.
Is there any alternative? Thanks.
We usually suggest avoiding the use of create because it may seem simple to use it but they usually violate the advanced requirements of RxJava. Instead, you should use one of the factory methods of Observable. In your case, the just factory method will get what you wanted: no final parameter:
public Observable<?> saveEventLog(#NonNull EventLog eventLog) {
return Observable
.just(eventLog)
.doOnNext(e -> {
DBEventLog log = new DBEventLog(e);
log.save();
})
.ignoreElements();
}

Categories

Resources