How do I test below method using mockito
public void showArg(String ss) {
if(ss == null) {
throw new NullPointerException();
}else if(ss.equals("")) {
throw new IllegalArgumentException();
}
// Log.d("",""+ss);
if(ss.equals("xyz")) {
this.show();
}else {
getResult(0);
}
}
In this example, there is nothing to be mocked. I just want to test the that is appropriate methods are called based on i/p.
If you want to verify that this method was called (assuming it was public), I suggest using a spy...
MyClass spy = Mockito.spy( myActualObject );
spy.showArg("xyz");
Mockito.verify(spy).show();
Spying (instead of mocking) means to take an actual object and "spy" on it, by wrapping it in another instance. This way you can call actual methods, but also check what was called and even modify what some methods will do, similar to mocking (the difference is, that a mock does not have an underlying "real" object, while a spy has).
As already mentioned you should use a spy to test such code. Additionaly looking at your code you should also test whether appropiate exceptions are thrown.
Code testing border cases can be looking like this:
#Test(expected = NullPointerException.class)
public void shouldThrowNullPointerExceptionWhenNullStringProvided() {
showArg(null);
}
#Test(expected = IllegalArgumentException.class)
public void shouldThrowIllegarArgumentExceptionWhenEmptyStringProvided() {
showArg("");
}
Related
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.
I have a MVVM architecture in my Android app. In an activity, I invoke a method to try to create something from service/repository and return it. I am using RxJava.
Here is the flow:
I click something in view, it invokes method in the Activity.
Method in Activity invokes method in ViewModel.
Method in ViewModel invokes method in Interactor(/use-case).
Interactor has access to service and tries to create something from that service.
Here is the code for this:
Activity:
#Override
public void onCreateWalletClick(String password) {
addWalletViewModel.createWallet(password);
}
ViewModel:
public class AddWalletViewModel extends BaseViewModel {
private AddWalletInteractor addWalletInteractor;
private final MutableLiveData<Wallet> newWallet = new MutableLiveData<Wallet>();
private final MutableLiveData<ErrorCarrier> newWalletError = new MutableLiveData<ErrorCarrier>();
public LiveData<Wallet> newWallet() {
return newWallet;
}
public AddWalletViewModel(AddWalletInteractor addWalletInteractor) {
this.addWalletInteractor = addWalletInteractor;
}
public Single<Wallet> createWallet(String password){
return addWalletInteractor.addWallet(password)
.subscribe(wallet -> newWallet.postValue(wallet), this::addErrorToLiveData);
}
private void addErrorToLiveData(Throwable throwable){
newWalletError.postValue(new ErrorCarrier());
}
}
Interactor:
public class AddWalletInteractor {
private final KeyStoreServiceInterface keyStoreServiceInterface;
public AddWalletInteractor(KeyStoreServiceInterface keyStoreServiceInterface) {
this.keyStoreServiceInterface = keyStoreServiceInterface;
}
public Single<Wallet> addWallet(String password){
return keyStoreServiceInterface.
createWalletAndReturnWallet(password);
}
}
Service:
#Override
public Single<Wallet[]> getAllWallets() {
return Single.fromCallable(()-> {
Accounts accounts = keyStore.getAccounts();
int amount = (int) accounts.size();
Wallet[] wallets = new Wallet[amount];
for (int i = 0; i<amount; i++){
org.ethereum.geth.Account gethAccount = accounts.get(i);
wallets[i] = new Wallet(gethAccount.getAddress().getHex().toLowerCase());
}
return wallets;
}).subscribeOn(Schedulers.io());
}
Problem is I can not manage to get this to work by tweaking the code. Right now it forces me to cast to (Single) in the return of the createWallet() method in the viewmodel. When running the app, it crashes in that method with:
java.lang.ClassCastException:
io.reactivex.internal.observers.ConsumerSingleObserver cannot be cast
to io.reactivex.Single
at addwallet.AddWalletViewModel.createWallet(AddWalletViewModel.java:31)
Please keep in mind I am new to RxJava, I am still trying to figure it out. Any suggestions here?
The cast performed in the createWallet method will always fail.
Solution 1
The simplest way to fix the crash is to change the return type of that method to io.reactivex.disposables.Disposable, assuming you're using RxJava 2. If you're using RxJava 1, then have it return rx.Subscription. The code you presented that calls the createWallet method doesn't seem to use the returned value so it shouldn't make a difference.
Solution 2
If you really do need the return type to be Single and you want to keep the same behavior, then an alternate solution would be to change the createWallet method as follows:
public Single<Wallet> createWallet(String password) {
return addWalletInteractor.addWallet(password)
.doOnSuccess(wallet -> newWallet.postValue(wallet))
.doOnError(this::addErrorToLiveData);
}
The method now returns a new Single that does whatever the Single returned from addWallet does and additionally invokes the appropriate lambda function when a value is successfully emitted or an error occurs. You would also need to modify the call site for the method as follows:
#Override
public void onCreateWalletClick(String password) {
addWalletViewModel.createWallet(password).subscribe();
}
That subscribe call is needed to have the Single start emitting values. It takes no parameters because you already do all of the interesting work in the createWallet method itself. Both snippets were written with RxJava 2 in mind, but I believe they will also work in RxJava 1 as is.
If you haven't already done so, you should check out the official Rx website as it provides a ton of information on how reactive streams work and how to use them.
Since you're new to RxJava and the documentation is so vast, here's a brief overview of the subscription concept and how it applies to your situation.
RxJava and other stream-based libraries like it have two main components: producers and consumers. Producers supply values and consumers do something with those supplied values.
Single is a kind of producer that only produces one value before terminating. In your case, it produces a reference to the newly created wallet. In order to do something with that reference, it needs to be consumed. That's what the subscribe method on the Single class does. When the Single returned by the addWallet method produces a value, the lambda passed to the subscribe method is invoked and the wallet parameter in that lambda is set to the produced value.
The return type of the subscribe method is NOT itself a Single. When a consumer and a producer are coupled together by the subscribe method, it forms a connection which is represented by the Disposable class. An instance of that class has methods to cancel the connection before the producer is done producing values or to check if the connection has been cancelled. It is this connection object that is returned by the subscribe method.
Note that until this connection is made via one of the subscribe overloads, the producer will not start producing items. I.e., a Single that is never subscribed to will never do anything. It's analogous to a Runnable whose run method is never called.
I have this class with these structure and i need test the behaviour of OnRequestListOfLunchsFinished interface
#Override
public void getListOfLunchs(final OnRequestListOfLunchsFinished callback) {
zip().onErrorResumeNext(new Function<Throwable, ObservableSource<? extends LunchServiceResponse>>() {
#Override
public ObservableSource<? extends LunchServiceResponse> apply(#NonNull Throwable throwable) throws Exception {
callback.onError(new RuntimeException(throwable));
callback.onEnd();
return Observable.empty();
}
}).subscribe(new Consumer<LunchServiceResponse>() {
#Override
public void accept(LunchServiceResponse response) throws Exception {
List<Lunch> result = new ArrayList<>();
List<IngredientResponseVO> ingredients = response.getIngredients();
Map<Integer, Ingredient> hash = new HashMap<Integer, Ingredient>();
for (IngredientResponseVO vo : ingredients)
hash.put(vo.id, new Ingredient(vo.id, vo.name, new BigDecimal(vo.price.toString()), vo.image));
for(InfoLunchResponseVO vo: response.getLunch()){
Lunch lunch = new Lunch();
lunch.setId(vo.id);
lunch.setImage(vo.image);
lunch.setName(vo.name);
for(Integer id : vo.ingredients){
Ingredient ingredient = hash.get(id);
lunch.addIngredient(ingredient);
}
result.add(lunch);
}
callback.onSuccess(result);
callback.onEnd();
}
});
callback.onStart();
}
private Observable<LunchServiceResponse> zip(){
return Observable.zip(getRequestOfListOfLunchs(), getRequestOfListOfIngredients(), new BiFunction<List<InfoLunchResponseVO>, List<IngredientResponseVO>, LunchServiceResponse>() {
#Override
public LunchServiceResponse apply(#NonNull List<InfoLunchResponseVO> infoLunchResponseVOs, #NonNull List<IngredientResponseVO> ingredientResponseVOs) throws Exception {
return new LunchServiceResponse(infoLunchResponseVOs, ingredientResponseVOs);
}
});
}
i have this test method
#Test
public void teste(){
List<IngredientResponseVO> ingredients = Collections.emptyList();
List<InfoLunchResponseVO> lunchs = Collections.emptyList();
when(mockApi.getListOfIngredients()).thenReturn(Observable.just(ingredients));
when(mockApi.getLunchs()).thenReturn(Observable.just(lunchs));
mockImplementation.getListOfLunchs(callback);
InOrder order = inOrder(callback);
order.verify(callback).onStart();
order.verify(callback).onSuccess(anyList());
order.verify(callback).onEnd();
order.verifyNoMoreInteractions();
}
but i am receiving the exception:
org.mockito.exceptions.verification.VerificationInOrderFailure:
Verification in order failure
Wanted but not invoked:
callback.onSuccess(<any>);
if i do this:
callback.onStart();
callback.onSuccess(Collections.<Lunch>emptyList());
callback.onEnd();
InOrder order = inOrder(callback);
order.verify(callback).onStart();
order.verify(callback).onSuccess(anyList());
order.verify(callback).onEnd();
order.verifyNoMoreInteractions();
this works.
how verify only calls of my mock callback?
You just must not use the InOrder object.
mockImplementation.getListOfLunchs(callback);
Mockito.verify(callback).onStart();
Mockito.verify(callback).onSuccess(anyList());
Mockito.verify(callback).onEnd();
Mockito.verifyNoMoreInteractions();
AFAICS the issue is not with the test but with your reading of the test results (jumping ahead: I believe it found a bug in your code).
Probably in the real code your getListOfIngredients and getLunchs do some network requests i.e. they are asynchronous to the call to getListOfLunchs and (zip inside of it). Thus in the real code onStart is called immediately on the caller thread while onSucess and onEnd are called later. However in your test you mock those API calls with very synchronous Observable.just and thus the order of execution is different: first onSuccess is called, then onEnd and finally onStart (you can easily validate this if you substitute your mocked callback with a custom one that just logs method name in every call).
You probably expeceted that since you use verifyNoMoreInteractions you would get a error about wrong order of onStart. Unfortunatelly this is not how it works. Since your order verifications are specified earlier, they are checked earlier. And in those checks there is yet no restriction of "no more". So what happens is roughly following:
onSucess is called. InOrder check ignores it because there was no onStart yet
onEnd is called. InOrder check ignores it because there was no onStart yet
onStart is called. This matches what InOrder expects and now it waits for onSucess. However this (second) onSuccess never comes and this is exactly what the error says.
So what to do? First of all I'd like to say that IMHO this failed test did find a very real bug in your code. Assume that at some point in the future someone added a caching layer to your API so sometimes getListOfIngredients and getLunchs return immediately with a synchronous result. In such case your code breaks contract of the OnRequestListOfLunchsFinished that onStart should be called first. So the proper way is to fix your code. An obvious but possible wrong way is to move the line
callback.onStart();
to the start of the method. (Why it is possibly wrong? Can your zip throw an Exception? If it does, what happens to the state of the callback?). Another way is to do the same as you do with onEnd i.e. copy it inside both success and error handling code in proper order.
mockito-core:2.7.10
I am testing the following method using mockito
#Override
public void detachView() {
mMovieListViewContract = null;
mMovieModelContract.releaseResources();
}
I am stubbing the releaseResources method which has a void return. And testing to ensure the stubbed version gets called only once.
#Override
public void releaseResources() {
if(mSubscription != null && !mSubscription.isUnsubscribed()) {
mSubscription.unsubscribe();
}
}
I have written the following test:
#Test
public void shouldReleaseModelResourcesWhenDetached() {
doNothing().when(mockMovieListModelContract).releaseResources();
movieListPresenterContract.detachView();
verify(mockMovieListModelContract, times(1)).releaseResources();
}
I want to verify that the stubbed version of mockMovieListModelContract.releaseResources() gets called just once.
The following failed the test:
verify(mockMovieListModelContract, times(1)).releaseResources();
The test failed with:
Wanted but not invoked:
movieListModelContract.releaseResources();
Actually, there were zero interactions with this mock.
So I changed to using verifyZeroInteractions(mockMovieListModelContract); which passed the test. However, the test to verify that the stubbed version gets called just once.
Kind of straight forward: the mocking framework tells you that this method wasn't invoked on that mock object.
There are only two explanations for that:
You are not really running the production code you are showing in your question (you are testing something else)
Something is wrong with your setup; and you are not "inserting" the mocked object when doing the test setup
I have a Tool class with two static methods, doSomething(Object) and callDoSomething(). The names are intuitive in that callDoSomething delegates its call to doSomething(Object);
public class Tool
{
public static void doSomething( Object o )
{
}
public static void callDoSomething()
{
doSomething( new Object());
}
}
I have a Test class for Tool and I'd like to verify if doSomething(Object) was called (I want to do Argument Matching too in the future)
#RunWith( PowerMockRunner.class )
#PrepareForTest( { Tool.class } )
public class ToolTest
{
#Test
public void toolTest()
{
PowerMockito.mockStatic( Tool.class );
Tool.callDoSomething();// error!!
//Tool.doSomething();// this works! it gets verified!
PowerMockito.verifyStatic();
Tool.doSomething( Mockito.argThat( new MyArgMatcher() ) );
}
class MyArgMatcher extends ArgumentMatcher<Object>
{
#Override
public boolean matches( Object argument )
{
return true;
}
}
}
Verify picks up doSomething(Object) if it's called directly. I've commented this code out above. Verify does NOT pick up doSomething(Object) when using callDoSomething, (this is the code shown above). This is my error log when running the code above:
Wanted but not invoked tool.doSomething(null);
However, there were other interactions with this mock.
at org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl.performIntercept(MockitoMethodInvocationControl.java:260)
at org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl.invoke(MockitoMethodInvocationControl.java:192)
at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:105)
at org.powermock.core.MockGateway.methodCall(MockGateway.java:60)
at Tool.doSomething(Tool.java)
at ToolTest.toolTest(ToolTest.java:22)
... [truncated]
I'd like to avoid making any changes to the Tool class. My question is, how can I verify doSomething(Object) was called from callDoSomething(), as well as perform some argument matching on doSomething's param
It sounds like you want to use a static spy (partial mock). The section of the PowerMock documentation that talks about mocking static has a note in the second bullet that could be easily missed:
(use PowerMockito.spy(class) to mock a specific method)
Note, in your example you're not actually mocking the behavior, just verifying the method is called. There's a subtle but important difference. If you don't want doSomething(Object) to be called you'd need to do something like this:
#Test
public void toolTest() {
PowerMockito.spy(Tool.class); //This will call real methods by default.
//This will suppress the method call.
PowerMockito.doNothing().when(Tool.class);
Tool.doSomething(Mockito.argThat( new MyArgMatcher() ));
Tool.callDoSomething();
//The rest isn't needed since you're already mocking the behavior
//but you can still leave it in if you'd like.
PowerMockito.verifyStatic();
Tool.doSomething(Mockito.argThat( new MyArgMatcher() ));
}
If you still want the method to fire though, just remove the two lines for doNothing(). (I added a simple System.out.println("do something " + o); to my version of Tool.java as an additional verification of doNothing().)
You can do your validation with this:
public class Tool{
public static boolean isFromCallDoSomethingMethod= false;
public static void doSomething(Object o){
}
public static void callDoSomething() {
doSomething(new Object());
isFromCallDoSomethingMethod= true;
}
}
You can do the verification as:
if(Tool.isFromCallDoSomethingMethod){
//you called doSomething() from callDoSomething();
}
REMEMBER
Don't forget to do the validation if you call the doSomething() from another way that is not from callDoSomething(), you can do this by ussing Tool.isFromCallDoSomethingMethod = false
Is this what you want?