How to write unit test for RxJava CompositeSubscription - android

#Override public void onBarcodeReceived(final String barcode) {
view.showProgress();
if (!textUtil.isEmpty(barcode)) {
subscriptions.add(
interactor.getSearchResultByBarcode(barcode).subscribe(subscriberForSearchResults(true)));
}
}
private Subscriber<PriceAndStockActivityViewModel> subscriberForSearchResults(
boolean fromBarcode) {
return new BaseSubscriber<PriceAndStockActivityViewModel>() {
#Override public void onNext(PriceAndStockActivityViewModel priceAndStockActivityViewModel) {
super.onNext(priceAndStockActivityViewModel);
view.updateView(priceAndStockActivityViewModel);
}
#Override public void onError(Throwable e) {
super.onError(e);
view.hideProgress();
view.organizeScreenComponentsByVisibility(true);
view.onError(e);
}
};
}
I've wanted to test method called onBarcodeReceived like below
#Test public void should_updateViewByViewModel_when_AnyBarcodeReceived() {
String barcode = "123123123";
PriceAndStockActivityViewModel viewModel = getPriceAndStockActivityViewModel(barcode);
when(textUtil.isEmpty(barcode)).thenReturn(false);
when(interactor.getSearchResultByBarcode(anyString())).thenReturn(Observable.just(viewModel));
presenter.onBarcodeReceived(barcode);
verify(view).showProgress();
verify(interactor).getSearchResultByBarcode(anyString());
verify(view).updateView(any(PriceAndStockActivityViewModel.class));
}
Since onNext runs in a different thread its normal not to reach view.updateView. It looks simple but I couldn't find how to solve it. Is there any way to verify updateView?

I presume getSearchResultByBarcode() works on a background thread. So I wonder how you're able to change your UI from this background thread?
I'd change the execution of your subscriber to Android's main thread, so that you can safely manipulate the view, regardless if the thread of getSearchResultByBarcode() changes in the future. However will not hardcode the Scheduler directly, rather lets inject it in the presenter class, for example via the constructor. Of course when you're creating the "real" presenter, you'd pass in AndroidSchedulers.mainThread():
public MyPresenter(, Scheduler observeScheduler) {
...
this.observeScheduler = observeScheduler;
}
....
#Override
public void onBarcodeReceived(final String barcode) {
view.showProgress();
if (!textUtil.isEmpty(barcode)) {
subscriptions.add(interactor.getSearchResultByBarcode(barcode)
.observeOn(observeScheduler)
.subscribe(subscriberForSearchResults(true)));
}
}
Then in your test, when constructing the Presenter you'd use Schedulers.immediate() (if you're using RxJava 1.x or Schedulers.trampoline() if you're using RxJava 2.x version. That should work without using any timeout()s in your Unit tests with Mockito ... after all you want them to run as fast as possible.
And one unrelated thing - you can use org.apache.commons.lang3.StringUtils as a substitution of android.text.TextUtils - it has roughly the same functionality but you won't need to mock it in your unit tests.

In order to wait for another thread to complete you can use this Mockito feature: verify with timeout.
verify(view, timeout(100)).updateView(any(PriceAndStockActivityViewModel.class));
Or use some means of thread synchronization like CountDownLatch. See example for Mockito here.

Related

How to switch out AndroidX Architecture Component task executor for Espresso tests

We've run into problems with a flakey Espresso tests and are pretty certain the cause is a LiveData#postValue call. It seems Espresso will sometimes make assertions before all tasks have been executed on the ArchTaskExecutor instance.
It seemed to me that this problem should be solveable with use of IdlingResource: we could swap out the ArchTaskExecutor for one we integrate with CountingIdlingResource to make sure Espresso is aware of tasks being executed. It seems however that it isn't possible to set the executor being used as ArchTaskExecutor#setDelegate is only available within the arch library itself. We could of course stop using postValue and use a Handler (with the main looper) integrated with CountingIdlingResource. So we don't have to do that is there any other way of switching out or integrating with the ArchTaskExecutor to have Espresso be aware of when and when not it's idle?
After doing some digging I found that CountingTaskExecutorRule is available in the AndroidX Arch package. This can be used to build out an idling resource like so:
public class CountingTaskExecutorIdlingResource extends CountingTaskExecutorRule implements IdlingResource {
private IdlingResource.ResourceCallback resourceCallback;
#Override
public String getName() {
return CountingTaskExecutorIdlingResource.class.getName();
}
#Override
public boolean isIdleNow() {
return isIdle();
}
#Override
public void registerIdleTransitionCallback(IdlingResource.ResourceCallback resourceCallback) {
this.resourceCallback = resourceCallback;
}
#Override
protected void onIdle() {
resourceCallback.onTransitionToIdle();
}
}

How to test void method with Mockito's doAnswer

I am new to Mockito and trying to understand how to use doAnswer in order to test a void method.
Here's my class with the onDestroy method to test:
public class TPresenter implements TContract.Presenter {
private CompositeSubscription viewSubscription;
//.......
#Override public void onCreate(.......) {
this.viewSubscription = new CompositeSubscription();
//.......
}
#Override public void onDestroy() {
if(viewSubscription != null && !viewSubscription.isUnsubscribed()) {
viewSubscription.unsubscribe();
}
}
Now I want to write a test for onDestroy() namely to verify that after executing onDestroy the subscription is unsubscribed. I found several examples to use doAnswer for testing void methods, for example here, and also here but I do not understand them.
Please show how to test the method onDestroy.
The normal way how you could test your onDestroy() would be based on viewSubscription being a mocked object. And then you would do something like:
#Test
public testOnDestroyWithoutUnsubscribe() {
when(mockedSubscription.isUnsubscribed()).thenReturn(false);
//... trigger onDestroy()
verifyNoMoreInteractions(mockedSubscription);
}
#Test
public testOnDestroyWithUnsubscribe() {
when(mockedSubscription.isUnsubscribed()).thenReturn(true);
//... trigger onDestroy()
verify
verify(mockedSubscription, times(1)).unsubscribe();
}
In other words: you create a mocked object, and you configure it to take both paths that are possible. Then you verify that the expected actions took place (or not, that is what the first test case does: ensure you do not unsubscribe).
Of course, you can't test the "subscription object is null" case (besides making it null, and ensuring that no NPE gets thrown when triggering the onDestroy()!
Given the comment by the OP: one doesn't necessarily have to use mocking here. But when you want to test a void method, your options are pretty limited. You have to observe side effects somehow!
If you can get a non-mocked viewSubscription instance to do that, fine, then do that. But if not, then somehow inserting a mocked instance is your next best choice. How to do the "dependency injection" depends on the exact context, such as the mocking/testing frameworks you are using.
Testing void methods in your main class under test is not a problem as does not require doAnswer.
Here is an example of how could you go about testing the call to unsubscribe.
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class TPresenterTest {
#InjectMocks
private TPresenter target = new TPresenter();
#Mock
private CompositeSubscription viewSubscription;
#Test
public void onDestroyShouldUnsubscribeWhenSubscriptionNotNullAndUnsubscribed() {
when(viewSubscription.isUnsubscribed()).thenReturn(false);
target.onDestroy();
verify(viewSubscription).unsubscribe();
}
#Test
public void onDestroyShouldNotUnsubscribeWhenSubscriptionNotNullAndNotUnsubscribed() {
when(viewSubscription.isUnsubscribed()).thenReturn(true);
target.onDestroy();
verify(viewSubscription, never()).unsubscribe();
}
}
As I mentioned in my comment to #GhostCat 's answer, my example is in fact un-testable because of the "new" instance of CompositeSubscription class. I would have to re-factor it and #GhostCat 's comment to his/her answer shows a way to do it.

How to perform #After for a specific JUnit test case?

I'm using Espresso to build UI tests. For some test cases I would like to call a specific after step to reset the state in case the script fails.
Is there a way to perform an #After step for a single JUnit test case (#Test)?
The only solution I can think of is to make a separate test class. But I would like the test cases to be grouped in the same test class.
It does sound a little odd ;) but ...
You could add a try/finally to the single test for which you want this after behaviour. For example:
#Test
public void testA() {
try {
// the body of testA
} finally {
// apply the 'after' behaviour for testA
}
}
Or, if you really want to use JUnit's #After then you could use the TestName Rule (since JUnit 4.7) as follows:
#Rule
public TestName testName = new TestName();
#After
public void conditionalAfter() {
if ("testB".equals(testName.getMethodName())) {
System.out.println("apply the 'after' behaviour for testB");
}
}
#Test
public void testA() {
}
#Test
public void testB() {
}

Android test method called after presenter executes retrofit call

I'm using Mockito to test my views but my tests are failing because of a method that is supposed to be called after a retrofit call is complete. How can I mock a view who's method is called by presenter after completion of a retrofit call? I'd like to verify that unBlockUI() below has been called. My tests show blockUI() is called but unblockUI() is not being called.
I get a fail message
Wanted but not invoked:
view.unBlockUI();
In my presenter I have the method
public void fetchResults(){
view.blockUI();
ResultsDataService resultsDataService = new ResultsDataService()
resultsDataService.getAllResults(new Callback<Catalog>() {
#Override
public void onResponse(Call<Catalog> call, Response<Catalog> response) {
view.unBlockUI();
}
#Override
public void onFailure(Call<Catalog> call, Throwable t) {
view.unBlockUI();
t.printStackTrace();
}
})
}
Results data service.
public class ResultsDataService {
private final RestApi restApi;
public CatalogDataService() {
//here I have a class that builds the REST Service
restApi = RestServiceBuilder.createService(RestApi.class);
}
public void getAllResults() {
Call<Catalog> call = restApi.getAllResults();
call.enqueue(callback);
}
}
my test method
#Test
public void shouldFetchAllResults_allOK() {
presenter.fetchResults();`
verify(view).blockUI();//This is called
verify(view).unBlockUI();//this is not called
}
I think one possible solution is to mock ResultsDataService to call the onResponse method of any callback every time getAllResults is called.
Unfortunately, the way you're creating your ResultsDataService inside fetchResults makes it really hard to do this. This is what we call tight coupling. You have a method that depends strictly on ResultsDataService with no chance to change it. Therefore you cannot control the presenter from the outside. As a rule of thumb, every time you see the new operator that's a sign of tight coupling.
Usually we use dependency injection to solve this. One way you can do it in your code is simply change the fetchResults method to receive the service as an argument:
public void fetchResults(#NonNull ResultsDataService service) {
// ...
}
It might not seem much, but now in the test you can pass in a configured mock and in your app you just pass in the real service.
Say now in your test you'd configure a mock like so:
ResultDataService service = mock(ResultDataService.class);
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call call = (Call) invocation.getArgument(0);
call.onResponse(call, <some response here>);
return null;
}
}).when(service.getAllResults(any(Call.class)));
You can now use this to pass it to your presenter fetchResults.
What does the mock above do? It will call the onResponse method of the passed in argument. So basically it will call right away the onResponse callback when you call fetchResults. In your case this will in turn call unBlockUI.
Notice you can do something similar to test the onFailure. You should also make ResultsDataService an interface, so your presenter doesn't depend on concrete implementations, but just interfaces. This is much more flexible.
Hope this helps. Remember, this is one way of doing this and not the single way.

How to assertion a void method in Robolectric Unit Test

How to verify a void method call in Robolectric test case where as no data coming out the called method.
What to assert in this case? Below given an example of the requirement.
public class SampleClass(){
final String TAG = SampleClass.class.getSimpleName();
public void log(){
Log.d(TAG, "Entry Loggd");
}
}
#Test
public void logEntry_test(){
SampleClass sc = new SampleClass();
sc.log();
// What to assert here to verify this log method
}
First off, good on you for writing tests!!! There are a few ways to go about testing that an internal logger is called. It's equally as important to understand what you're looking to test. Testing that a class is logging a specific message is most likely a fragile test, so be fore-warned that you probably don't need it.
Method #1: Using Robolectric
Robolectic documentation doesn't lend itself to answering basic questions, but its codebase is very well documented with its tests. A basic understanding of its principles and how shadows work can get you a long way. ShadowLog tests lay the ground work to this solution.
#RunWith(RobolectricTestRunner.class)
public class SampleClassTest {
#Test
public void log_writesExpectedMessage() {
new SampleClass().log();
ShadowLog.LogItem lastLog = ShadowLog.getLogs().get(0);
assertThat(lastLog.msg).isEqualTo("some message");
// or
assertThat(lastLog.msg).isNotNull();
}
}
Tests using Robolectric v3.1.2
Add the following to your build.gradle file:
testCompile 'org.robolectric:robolectric:3.1.2'
Method #2: Making use of Abstractions
If your sample class derives from an Android class (Activity, Fragment, Application, etc), then using android.util.Log makes sense, but bear in mind that your test will need to be a Robolectric or AndroidInstrumented test. If your SampleClass is just some POJO, then using a simple logging framework may make your testing efforts easier. For example, using Jake Wharton's Timber, your class and test can be written as follows:
import timber.log.Timber;
public class SampleClass {
void log() {
Timber.d("some message");
}
}
// SampleClassTest.java
public class SampleClassTest {
// setting up a Tree instance that we define below
TestTree testTree = new TestTree();
#Test
public void log_writesExpectedMessage() {
// setting up Timber to us the test classes log writer
Timber.plant(testTree);
// invoke the logging function
new SampleClass().log();
// assert
assertThat(testTree.lastMessage).isEqualTo("some message");
}
private class TestTree extends Timber.Tree {
private String lastMessage;
#Override
protected void log(int priority, String tag, String message, Throwable t) {
lastMessage = message;
}
}
}
Good luck, happy testing!
In my understanding you want to mock static methods. I guess, using static mocks are not the most elegant way to testing. Better to use an abstraction as recommended by abest. Although, it can be done with PowerMock.

Categories

Resources