Forming Mockito "grammars" - java

Mockito seems like a pretty sweet stubbing/mocking framework for Java. The only problem is I can't find any concrete documentation on the best ways of using their API. Common methods used in tests include:
doXXX(???) : Stubber
when(T) : OngoingStubbing
then(T) : OngoingStubbing
verify(???) : T
given(T) : BDDOngoingStubbing
willXXX(???) : BDDStubber
When you see examples of Mockito in practice, you see code like:
when(yourMethod()).thenReturn(5);
From all the docs I've read, I've identified several "patterns" of Mockito "grammars" obtained from daisy-chaining these method calls together like the example above. Some common patterns I've found are:
When/Then: when(yourMethod()).thenReturn(5);
Given/Will: given(yourMethod()).willThrow(OutOfMemoryException.class);
Do/When: doReturn(7).when(yourMock.fizzBuzz());
Will/Given/Do: willReturn(any()).given(yourMethod()).doNothing();
Verify/Do: verify(yourMethod()).doThrow(SomeException.class);
What I'm choking on is how to select the right pattern/combination of method calls to model my test cases. It seems like you can daisy-chain these together in seemingly endless combos and I'm not sure what pattern is right for which problem.
Can some Mockito Guru help shed some light as to which patterns/combinations of Mockito methods are used for which types of test cases (and why)? Thanks in advance!

There are several disadvantages to the when/thenReturn, when/thenThrow and when/then syntaxes. For example,
In the case of when/thenReturn, if the return type is a generic with a
wildcard, and you wish to return a mock of the same type, you will be unable
to avoid a compile warning.
You can't use when/thenThrow and when/then for a void method.
You can't use these syntaxes on Mockito spies.
You can only call when once for each combination of mock object,
method and arguments, unless you call reset on the mock.
Calling when multiple times for one combination of mock
object and method, when you are using argument matchers, can lead to problems.
I find these cases difficult to remember. So instead of trying to keep track of when the
when/thenReturn, when/thenThrow and when/then syntaxes will and won't work, I prefer to avoid them completely, in favour of the doReturn/when, doThrow/when and doAnswer/when alternatives. That is to say, since you'll occasionally need doReturn/when, doThrow/when and doAnswer/when, and you can ALWAYS use these methods, there is no point in learning how to use when/thenReturn, when/thenThrow and when/then.
Note that doReturn, doThrow and doAnswer can be chained together in the same way as thenReturn, thenThrow and then. What they don't have is an option for returning several values (or throwing several exceptions, or running several answers) within a single call to doReturn, doThrow and doAnswer. But I find that I need to do this so seldom, that it doesn't really matter.
There's one more disadvantage to doReturn, which I consider insignificant. You don't get compile time checking of the type of its argument, like you do with when/thenReturn. So if you get the argument type wrong, you won't find out until you run your test. Frankly, I don't care.
In summary then, I have been using Mockito for more than two years, and I consider the consistent use of doReturn, doThrow and doAnswer to be a Mockito best practice. Other Mockito users disagree.

Mockito often have several ways of doing things.
I find myself using mostly:
// Setup expectations
when(object.method()).thenReturn(value);
when(object.method()).thenThrow(exception);
doThrow(exception).when(object.voidMethod());
// verify things
verify(object, times(2)).method();
verify(object, times(1)).voidMethod();
I've found that i can do 95% of what i need to with these three kinds of calls.
Also, what version of Mockito are you using? "given" and "will" constructs are not present in the latest version (1.9.0+)
However, there are cases where I want the return value or exception to respond to the input. In this case, you can use the Answer interface to inspect the method arguments and return an appropriate value.
public class ReturnFirstArg<T> implements Answer<T> {
public T answer(InvocationOnMock invocation) {
return invocation.getArguments()[0];
}
}
when(object.method(7)).thenAnswer(new ReturnFirstArg<Integer>());

The things in fact looks much simpler than you thought
REF: http://static.javadoc.io/org.mockito/mockito-core/2.7.12/org/mockito/Mockito.html
Verify:
In order to use Mockito, you need to understand one basic philosophy of Mockito: Stubbing and Verification is separated. Therefore, the "Verify/Do" you mentioned is in fact doing the "Verification" job, while the other 4 "grammars" is for stubbing. Stubbing define how the mock object will react in different situation. Verification is to make sure what the mocks is invoked as expected, in previous invocation to system under test (SUT).
When/Then , Given/Will:
Then it come to the "When" and "Given" families. You can simply treat them as aliases of each other. "Given" family is added in Mockito 1.8.x as to make it looks more aligned to BDD practices.
DoXxx:
In normal case we mostly use when(xxx).then(...) (and given(...).will(...) ) . However there are some case that syntax is not working. The most obvious case is when return type of the stubbed method is void. In such case when(mockObj.voidMethod()).thenThrow(anException) is not going to compile. As a workaround, an alternative syntax of Do/When is created, so you can write the previous line as doThrow(anException).when(mockObj.voidMethod())

Related

Should I use Mockito doAnswer for testing a delete method in Java?

I want to write a Unit Test for testing productRepository.delete method:
public void delete(UUID uuid) {
final Product product = productRepository.findByUuid(uuid)
.orElseThrow(() -> new EntityNotFoundException(PRODUCT));
productRepository.delete(product);
}
However, I have really no idea on what is the proper approach for testing this method. Some approaches use verify, but I think it is not good idea as it just check if the productRepository's delete method is called or not. Instead of this, I am thinking something e.g. doAnswer(AdditionalAnswers.returnsFirstArg()).when(productRepository).delete(any());, but not sure if this is the most proper way for testing productRepository.delete. So, how can I test it properly?
You can test two things:
Verify that delete() is called with the right argument and
that the EntityNotFoundException is thrown for a non existant UUID
Best way to do this is by mocking the productRepository delete() method as you
mention and by throwing the expected exception on a call to
productRepository.findByUuid(uuid) when(productRepositoryMock.findByUuid(uuid)).thenThrow(new EntityNotFoundException(PRODUCT)));
The Mockito documentation makes a bit clearer:
For information solely on custom argument matchers check out javadoc for ArgumentMatcher class (for non-trivial method arguments used in stubbing or verification).
Be reasonable with using complicated argument matching. The natural matching style using equals() with occasional anyX() matchers tend to give clean & simple tests. Sometimes it's just better to refactor the code to allow equals() matching or even implement equals() method to help out with testing.

How should I mock Arrays.asList in Java Unit Test?

I have a Unit Test in a Java app and I get error while executing the following line:
when(Arrays.asList(Locale.getISOCountries()).contains(countryCode)).thenReturn(true);
The error message does not mention mocking, but I think the problem is related to not mocking
Arrays.asList(Locale.getISOCountries() part in the when method. So, how should I treat this line? Normally I mock services and repositoories, but ı am not sure if I should mock this part like #Mock Locale locale;. I tried it but not worked.
Here is the error message:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Boolean cannot be returned by toString()
toString() should return String
Note: I also tried doReturn(true).when(Arrays.asList(Locale.getISOCountries()).contains(countryCode)); but not worked.
TL;DR: don't try to mock this. For one thing, you can't; for another, you shouldn't.
It is best to use the default behavior. Remove the line where you attempt to configure this behavior with Mockito.
If you insist that you need to be able to use an arbitrary list of countries, see the section on "dependency injection" below, noting the caveat mentioned.
Attempting to mock the return value of Arrays.asList(Locale.getISOCountries()).contains(countryCode) would specifically mean that you are trying to alter the behavior of the List<String> returned by Arrays.asList when given a particular String[] as an argument.
You can't with Mockito, because it isn't magic: it doesn't allow replacement of behavior for arbitrary expressions.
The way something like when(aMock.method(123)).thenReturn("hello") works is that the mock object - aMock - records that method was invoked with an argument 123. This information is pushed onto a stack, from which the when method is able to retrieve it and deal with it.
The pushing-onto-the-stack is only done if aMock is an object that Mockito has created: Mockito implements the methods of an interface/overrides the methods of a class to do this recording.
None of the objects involved in Arrays.asList(Locale.getISOCountries()).contains("GB") were created by Mockito. As such, none of these objects have methods which capture the invocation and push it onto the stack; Mockito basically can't see that anything is going on, so when the when call comes, it's just using whatever state is hanging around in Mockito. The error message shown:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Boolean cannot be returned by toString()
toString() should return String
indicates that it thinks you are configuring the behavior of a toString method, nothing obviously to do with Arrays.asList, Locale.getISOCountries() or List.contains.
For the same reason, you can't mock the return value of Arrays.asList(Locale.getISOCountries()) or Locale.getISOCountries(): they're just not objects Mockito knows anything about.
So, that's why this mocking doesn't work. On to why you don't want to do it in the first place:
List.contains has specific semantics, namely that it returns true if and only if the argument is in the list. There are implications of this, such as aList.contains(o) == true implying that a call to aList.indexOf(o) would have returned a non-negative value.
This means that the consequences of mocking contains would be either:
You have to also configure the mocking of other methods on the list such that the behavior of the list is consistent with that result of List.contains (so, indexOf, subList, iterator etc) - and, how the mock should behave if you were to set the element equal to o to something else (because Arrays.asList allows that);
or
You don't configure the other mocking, and your List doesn't have behavior consistent with an actual List, which will have unpredictable effects on the behavior of your code.
But you don't actually have to worry about doing 1. (which is good, because it would be essentially impossible to do correctly, e.g. such that copies of the list have the same contains behavior) or 2. (which is good, because introducing the unpredictability of a broken List is simply a bad idea): Arrays.asList has a perfectly-working implementation of the List interface; all you need to make sure is that the argument you pass in (in this case Locale.getISOCountries()) contains the element that you want.
Mocking of the return value of Arrays.asList(...).contains is neither necessary nor desirable.
So, the problem now is shifted from one of ensuring that Arrays.asList(Locale.getISOCountries()).contains(countryCode) to one of ensuring that Locale.getISOCountries() has at least one element that is equal to countryCode.
As stated in the Javadoc of Locale.getISOCountries():
Returns a list of all 2-letter country codes defined in ISO 3166
Given that GB (as was originally asked) is a 2-letter country code defined in ISO 3166, it will always (or, at least, until ISO3166 is changed) be an element of the array returned by Locale.getISOCountries().
Hence, the array returned by Locale.getISOCountries() is going to contain "GB", so Arrays.asList(Locale.getISOCountries()).contains("GB"), without actually doing anything.
But then there is the question of making Arrays.asList(Locale.getISOCountries()).contains(countryCode) true, for an arbitrary countryCode. By the argument above, you want to effect this only by ensuring that Locale.getISOCountries() has an element equal to countryCode.
If countryCode is another two-letter ISO-3166-2 country code, this already works, as in the GB case.
If countryCode is not an ISO country code, you absolutely should not want to make a method return it if that method is documented to return only ISO-3166-2 country codes, because this wouldn't happen in production code.
Mocking should not be used as a way to do arbitrary things in tests.
You only ever want a test to test things which can actually happen in production code. Ideally, you use "the real thing"; test doubles (of which a mock is one type) come into play only if using "the real thing" is hard because the real thing is slow, expensive, difficult to reproduce (e.g. an error condition like a network error or full disk) etc. But, the testing double should only be doing things you'd see for real.
So, even if you could mock Locale.getISOCountries() to ensure that it returned an array containing a non-ISO-3166-2 countryCode, you shouldn't, because this will never actually happen in production; and a test that tests something that cannot happen in production has very limited value in telling you something useful.
Actually, you can mock static methods like Locale.getISOCountries() using PowerMock; but changing the behavior of a static method is highly inadvisable, because it doesn't just change the behavior for you - it changes it for anybody who calls it. So, there could be unintended consequences in the behavior, both nearby and in the rest of the code.
For example:
when(Arrays.asList(Locale.getISOCountries())).thenReturn(Collections.singletonList(countryCode.toUpperCase(Locale.ENGLISH)));
Aside from changing the mutability semantics of the returned list (Arrays.asList allows set; Collections.singletonList doesn't), it is now inconsistent with other country-code-returning methods in the Locale class (e.g. getISOCountryCodes(Type). Chasing down and fixing all such inconsistencies is nigh-on impossible.
What if we could use PowerMock to mock the return value of Arrays.asList(Locale.getISOCountries()), i.e. a less generic use-case of the Locale.getISOCountries() method? This still suffers from the problems of unintended consequences - there could be other parts of the program which invoke Arrays.asList(Locale.getISOCountries()) where the mocked behavior isn't desirable.
What if we could use PowerMock to mock the return value of just one specific call to Arrays.asList(Locale.getISOCountries())? That's brittle, for example, if another call is added, you'd have to make sure the test is correctly updated, otherwise the behavior would be inconsistent between the calls.
There isn't a good way to win the PowerMock battle.
There are an awful lot of words here, but the key point is that there are really rather difficult-to-deal-with consequences of trying to use mocking inappropriately: using the actual behavior (without mocks) is best; but, if a mock has to be used, it should not behave in a way that the real code never will.
Fortunately, Mockito is stopping you from doing this; but hopefully this answer has given a thorough explanation as to why it was the wrong approach in the first place.
Dependency injection
With all of this said, there is a way to make your code work in the face of arbitrary country codes: dependency injection.
Whilst there are lots of DI frameworks (e.g. Guice, Spring) which introduce a lot of power (and complexity and horror), dependency injection simply means: passing things as arguments.
If, for example, the code in which you want Arrays.asList(Locale.getISOCountries()).contains(countryCode) to be true occurs in a method, inject the country list as a parameter to that method:
class MyClass {
void myMethod(List<String> countryCodes, String countryCode) {
if (countryCodes.contains(countryCode)) {
// ...
}
}
}
or make it a constructor parameter:
class MyClass {
private final List<String> countryCodes;
MyClass(List<String> countryCodes) {
// Defensive copy.
this.countryCodes = Collections.unmodifiableList(new ArrayList<>(countryCodes));
}
void myMethod(String countryCode) {
if (countryCodes.contains(countryCode)) {
// ...
}
}
}
In your production code, pass in Arrays.asList(Locale.getISOCountries()); in test code, pass in whatever list you like.
But still: beware of the interaction between this code and code which uses Locale.getISOCountries() and allied methods directly in tests. If there is a risk of such an interaction, it remains safer to write your tests using the static Local.getISOCountries().

How to assert that methods are called with mockito

I want to ask more of a conceptual question related to testing. I am using Mockitos for my unit testing.
I have a method that does bunch of things. All the methods it calls internally are void methods, which in turn will do some other actions. The method under question can complete with exception or without exception. There is no scope for writing assert statements as it mostly calls void methods. Also, I have written independent unit test for all other methods of this class.
My question is if I need test coverage, I should write test case for all methods. But, I do not find any valid assert for one of my method. The method under question is an important method from unit test coverage perspective. When I run my test, I do see in logs that the methods executes fine but there is really nothing to assert. What should I do in such a situation?
1) Leave the method as is without any asserts? It still is checking if everything is working as expected
2) Create 2 methods one that expects exception ( Negative Testcase) and one regular test method with no asserts. ( This is to basically show I have covered both positive and negetive scenario). I still do not have any asserts here.
Is this the right approach to take or there is a better way for dealing with this problem?
If you don't have anything worth asserting, you can try verification instead.
verify(someMock, times(x)).someMethod();
More on verification with Mockito in the documentation: https://mockito.googlecode.com/hg-history/1.5/javadoc/org/mockito/Mockito.html
Why isn't there anything to assert? Let A be the universe if you run your method. Let B be the universe if you don't run your method. If A == B then stop calling the method, it's not doing anything. If A != B then assert that whatever is different about them is true.
i.e., what is your method actually doing? That should be part of your test.

Confused about advantages of MockUp vs Expectations

I just started using JMockit and am confused about the advantages of using MockUp for "Faking it" vs Expectations to mock an object.
From what I read through the docs, MockUp of a class allows me to override methods with my own implementations. However, I see that I can do things similarly in Expectations blocks.
So what is the advantage of a MockUp vs an Expectations? According to the JMockit docs,
Fakes are different from the mocking API in that, rather than
specifying in a test the invocations we expect a dependency will
receive when used by code under test, we modify the implementation of
the dependency so that it suits the needs of the test.
Isn't that just semantics? Functionally, are the same things not achievable using an Expectations() block instead of using a MockUp<>?
Your question is: What is difference between using Expectations and Mockup API?
I'm new to this, but to me that is mostly two different ways of doing the same thing. Which you pick is just matter of taste and how you want to test your code.
In Mockup API you can specify the mock in one statement block, whereas in Expectations you would use an Expectations block and a Verifications block. Otherwise they seem very similar to me too.

Guava preconditions checkNull, checkArgument

I want to check preconditions on a base class so that I know subtypes will always use constructor arguments that are valid.
Let's take as an example a constructor that:
takes 2 or more parameters
takes parameters of different types
for one parameter, it performs multiple checks (e.g. String is not null and not empty)
How would one best use the Guava preconditions approach in that case?
In a mock example like this: (this is contrived!)
protected AbstractException(String errorMessage, Throwable errorCause) {
super(errorMessage, errorCause);
checkNotNull(errorMessage,
ErrorMessage.MethodArgument.CANNOT_BE_NULL_CHECK, "errorMessage");
checkArgument(!errorMessage.isEmpty(),
ErrorMessage.MethodArgument.CANNOT_BE_EMPTY_STRING_CHECK,
"errorMessage");
checkNotNull(errorCause, ErrorMessage.MethodArgument.CANNOT_BE_NULL_CHECK,
"errorCause");
}
I end up calling super before checking the arguments because a call to super needs to be the first line of the method and, although I could do super(checkNoNull(errorMessage)), I cannot do the same wrapping using checkArgument because that returns void. So the dilemma is:
Where do I put the checks on all arguments? I don't want to create a Builder just for that
How do I "group" checks as in a fictitious checkStringNotNullAndNotEmpty()
Should I rather think about integration with matchers frameworks? (hamcrest, fest assertions...)
I use the odd-looking ErrorMessage.MethodArgument.CANNOT_BE_NULL_CHECK because the default throw does not include an error message so from the testing side I cannot recognise this as an argument validation failure rather than a "any" NPE?
Am I doing it all wrong?
This should have been a comment, but it's too long.
Calling super before the test is harmless provided that the super ctor doesn't do things which it shouldn't do anyway.
It could be prevented via a static builder method, you need no Builder. But it's not worth it.
I doubt that grouping tests is generally useful; if it was, then there would be a such method already. But if you need one such a concrete thing more than twice, then write your own; if it comes often, report it to the Guava team as an RFE.
I'm pretty sure, matchers are an overkill here as you're just creating an exception, i.e., something used only rarely (I hope). As your test is runtime only, it can't really help to catch errors. It would be nice, if you could statically ensure a "properly" constructed exception, but it's impossible in pure java.
More important: The exceptions you're throwing are probably inferior to the ones you'd get without all the checks. Imagine the user provides a cause and no message. That's bad, you think, but you replace it with an NPE lacking any cause. That's worse.
Look at Guava's Preconditions.format (package private). They could check the correct number of arguments first, but they do not. You can provide too few or too many, which is an error, but ignoring it is the best way to handle it.

Categories