JMock - several invocations with different arguments - java

The method I want to test is calling a mock method with different arguments:
public void methodToTest(){
getMock().doSomething(1);
getMock().doSomething(2);
getMock().doSomething(3);
}
In my unit test I want to know, if methodToTest really is calling those methods with exactly those arguments. This is the code I wrote:
#Test
public void myMockTest(){
oneOf(mock).doSomething(1);
oneOf(mock).doSomething(2);
oneOf(mock).doSomething(3);
}
At (2) I get an "Unexpected invocation" - as if it couldn't distinguish different arguments. So I've tried that one:
exactly(3).of(mock).doSomething(with(Matchers.anyOf(same(1), same(2), same(3))));
But this also didn't do what I've expected.
Finally, this one worked:
exactly(3).of(mock).doSomething(with(any(Integer.class)));
So I know, that my method was called 3 times with any Integer number. Is there any way to make sure, it's exactly the argument(s) I have passed?

Did you surround the expectations with a checking block?
context.checking(new Expectations() {{
oneOf(mock).doSomething(1);
oneOf(mock).doSomething(2);
oneOf(mock).doSomething(3);
}});
Also, are you aware the jmock does not enforce sequence unless you do so explicitly?

Related

Test lambda expressions called by dependencies

I am trying to test some code inside lambda expression which is a call back from another class.
class EmailSender {
private EmailBuilder emailBuilder;
public void send() {
String testEmail = emailBuilder.buildEmail("Test Email", bodyContentAppender());
//send testEmail
}
private Consumer<Email> bodyContentAppender() {
//how to test this through JUnit?
return email -> email.appendBody("Body Content");
}
}
interface EmailBuilder {
String buildEmail(String templateName, Consumer<Email> contentAppender);
}
The lambda expression in the method getBodyContent is called from EmailBuilder which is a mocked dependency in the JUnit test for EmailSender. Since I am mocking the behavior of EmailBuilder, the code inside getBodyContentis not called from tests. How to test such piece?
EDIT:
Capturing the lambda expression through Argument Captors is not a solution in this case as the behavior of EmailBuilder is mocked and the actual methods are not called. Secondly, email.appendBody does some transformations on an object which is passed by an external API and not straightforward to create.
What you are trying to do here is essentially to verify that a factory method did in fact really return the correct object. There is this related question, where the consensus is to not test the result of a factory method beyond verifying that it does indeed return an object of the correct type. The behavior of that object should be tested in the UnitTests for that type.
In an answer to this related question on unit testing lambdas Stuart Marks argues that
If the code in the lambda is complex enough that it warrants testing, maybe that code ought to be refactored out of the lambda, so that it can be tested using the usual techniques.
Now, the real question is: If this was not a lambda, but a concrete class MyBodyContentAppender that implements the functional interface Consumer<Email>, how would you unit test that? What kinds of test would you write for this class?
You would probably write tests to verify that, given an Email, invoking accept() does indeed invoke appendBody() with the appropriate parameters, perhaps that invoking it with a null argument throws a NullPointerException etc. You would possibly not verify that email.appendBody() works as expected, because that is covered by the tests for Email. You may have to mock Email for these tests if it is difficult to create.
Well, all of these tests can also be performed for the lambda. Your problem is that the factory and the type of the created object are both private, so from the perspective of your test, the only way to access that object is via the parameter passed to the (mocked) emailBuilder.buildEmail().
If you use Mockito for mocking the emailBuilder, you could capture the arguments to this method via ArgumentCaptors (see 15. Capturing arguments for further assertions (Since 1.8.0)), I'm sure other mocking libraries provide similar functionality.
Most mocking frameworks allow you to check arguments that are used when invoking methods on mocked object. Respectively, you can capture them.
So:
acquire the parameter passed
simply invoke the "code" that it represents, and check if that makes the expected updates to an Email object you provided.
It will be easier to test if you actually supply the body content as an argument, and make sure the method is public. If you intend to keep the method as private, then you should test the public method calling it.
public Consumer<Email> getBodyContent(String body) {
//how to test this through JUnit?
return email -> email.appendBody(body);
}
Then you can test it as
#Test
public void testGetBodyContent(){
.... //send different arguments and assert
....
}
So when you want to unit test your code you must ensure that it's doing one job at a time. You method is named as getBodyContent but seems like is supposed to do no more work than appending to email body. Hence, you could pull out this method to be public.
Now you could pass the body and get the content.
#Test
public void testGetBodyContent(){
consumer<Email> consumer = EmailSender.getBodyContent();
assertEquals("Email Content", consumer.accept(<mocked Email object>).getBody())
}

Mockito answer is getting invoked only once

I am trying to mock spring's applicationContext.getBean(String, Class) method in below manner -
when(applicationContext.getBean(Mockito.anyString(), Mockito.eq(SomeClass.class))).thenAnswer(
new Answer<SomeClass>() {
#Override
public SomeClass answer(InvocationOnMock invocation) throws Throwable {
// doing some stuff and returning the object of SomeClass
}
});
The scenario is that, the applicationContext.getBean method will be called a number of times, each time a with different strings but the same class (SomeClass.class).
The problem I am getting here is that the answer is getting invoked for the very first invocation of getBean method. With each subsequent invocation of getBean I am getting below exception -
******org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));******
Any idea, if I am missing something ?
#Kshitij
I have faced same issue in my previous project. I came across this below doc:
http://static.javadoc.io/org.mockito/mockito-core/2.16.0/org/mockito/Mockito.html#resetting_mocks
Under section 17 it is explained how to use reset()
Example: Let's say we have EvenOddService which finds whether number is even or odd then Test case with reset() will look like:
when(evenOddService.isEven(20)).thenReturn(true);
Assert.assertEquals(evenOddController.isEven(20), true);
//allows to reuse the mock
reset(evenOddService);
Assert.assertEquals(evenOddController.isEven(20), true);
Hope this helps :).
When using Mockito, you need to tell him how many times you will call your mock. You need to make as many when calls as you will need. For instance, if you know you'll test your method three times, you need to declare three separate when statements.
PS: I used Mockito for a bit only, it is possible that there is a solution to tell Mockito to use the same Answer multiple times in a row.
EDIT
Olivier Grégoire pointed out in the comments that you can use a single when call, but call thenAnswer multiple times. It is more elegant this way.
I've added this to my test class:
#AfterEach
public void resetMock(){
Mockito.reset(myMockedService);
}

mockito "verify" checks current state, but does not reset mock invocations

I'm using Mockito in my JUnit tests. The test is an integration test, testing a whole scenario, thus there are many assertions and verify(mock)s in it.
My problem is, that I'm writing some production code, doing some assertions and then verify the mock which works, until there is an identical mock invocation. see the simplified code:
interface I {
void m1();
void m2();
}
// some decorator
class T implements I {
public T(I decorated) {
/*...*/
}
/* ... */
}
public void testInvalid() {
I m = mock(I.class);
T t = new T(m);
t.m1();
assertEquals("m1", t.getLastMethod());
verify(m).m1();
t.m2();
assertEquals("m2", t.getLastMethod());
verify(m).m2();
t.m1();
assertEquals("m1", t.getLastMethod());
verify(m).m1();
// TooManyActualInvocations t.m1(): Wanted 1 time, but was 2 times ...
}
public void testValid() {
I m = mock(I.class);
T t = new T(m);
t.m1();
assertEquals("m1", t.getLastMethod());
t.m2();
assertEquals("m2", t.getLastMethod());
t.m1();
assertEquals("m1", t.getLastMethod());
verify(m, times(2)).m1();
verify(m).m2();
}
One idea is to verify the mocks at the end, but let's say there is a small stupid implementation mistake which leads to invoking the method m1 twice and m2 once but not as I would expect it in testInvalid but in the end the test would pass. I want my test to fail early. How do I accomplish that?
Thank you.
Thanks to #Woozy Coder:
Didn't mentioned, that reset would also be an option, but since it has to be called between verify and the next equal stub call, it makes it hard to write "nice" and correct tests, I think. There should be two different mocking styles:
"postcondition" mocking as Mockito does it
"early" mocking which would be an implicit reset after a verify-block
something like:
earlyReset(m).after(
new Runnable() {
t.someMethodInvokingTwoStubs();
verify(m).someMethod1();
verify(m).someMethod2();
}
);
I am having a similar problem and decided to use clearInvocations() (arrived in Mockito 2.1)
https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/Mockito.html#clearInvocations-T...-
Using reset() has the drawback that you loose your stubbing as well, clearInvocations() only clears the invocations.
Mockito was written to avoid brittleness, such that verification can make the least-specific assertion possible to allow for implementations to evolve without changing the test. If it doesn't matter to your test system that you're calling these methods multiple times, then you shouldn't ask Mockito to check it.
Alternatives:
Use atLeast or atLeastOnce to ensure the call happened at all without worrying how many additional times the method is called.
If the call is stubbed to have return values, infer that the system works from state assertions about the data you've stubbed.
If you really need stub or verification behavior to change across a single test method, your mock may grow outside the scope of what Mockito does well. Use an Answer for a single method, or write a manual Fake that simulates the interconnected methods properly.

Mockito.verify method contain boolean and argument captor

I don't know how can I use Mockito.verify in this case. How can I pass false to Mockito.verify? I try 2 different ways but it does not work.
public Sample someMethod(Sample s, boolean a){....}
#Test
public void test() {
...
verify(mock).someMethod(sampleCaptor.capture(), false));
verify(mock).someMethod(sampleCaptor.capture(), org.mockito.Matchers.eq(false)));
...
}
You have it right the second way:
verify(mock).someMethod(sampleCaptor.capture(), Matchers.eq(false));
When using Matchers (including ArgumentCaptor.capture), you have to use a Matcher for every value, because Matchers work via side-effects.
If the above doesn't work, you may be misusing matchers earlier in the method. It is sometimes helpful to explicitly call Mockito.validateMockitoUsage() immediately before your call to verify, to ensure that there's nothing wrong with Mockito's internal state. (Additional information about how it "does not work", including a minimal reproducible example, may be helpful in solving your specific case.)

How to mock a method call without actually calling its submethods

I started using JUnits (Mockito) from yesterday. I searched for similar question, but didn't find.
I have a class with method method1() which in turn calls method2().
I don't want to mock method2
I am mocking call to method1(). I was expecting that it would return the custom object(without going ahead and calling method2) which I want. But instead it proceeds and tries to call method2().
class A {
method1() {
//do something.
method2();
}
}
I mocked method1 and return any object (say new Integer(1)).
I dont want method2 to be called. but when I am debugging this Junit. It goes and calls method2. Hence fails.
When using syntax like this:
#Test public void yourTest() {
A mockA = Mockito.mock(A.class, Mockito.CALLS_REAL_METHODS);
when(mockA.method1()).thenReturn(Integer.valueOf(1));
}
then the first thing Java will do is to evaluate when(mockA.method1()), which requires calling mockA.method1() to get a value to pass into when. You don't notice this with other mocks, because Mockito mocks return nice default values, but with spies and CALLS_REAL_METHODS mocks this is a much bigger problem. Clearly, this syntax won't work.
Instead, use the methods beginning with do:
#Test public void yourTest() {
A mockA = Mockito.mock(A.class, Mockito.CALLS_REAL_METHODS);
doReturn(Integer.valueOf(1)).when(mockA).method1();
}
As part of .when(mockA), Mockito will instead return an instance that has no behavior, so the call to method1() never happens on a real instance. do syntax also works with void methods, which makes it more flexible than when(...).thenReturn(...) syntax. Some developers advocate for using doReturn all the time; I prefer thenReturn because it's slightly easier to read, and can also do return type checking for you.
As a side note, prefer Integer.valueOf(1) over new Integer(1) unless you absolutely need a brand new instance. Java keeps a cache of small integers, and this can be faster than allocating a brand new reference if you need to manually box an int into an Integer.
Usually you mock interfaces or abstract classes and provide implementations of abstract methods. In your case you want to substitute the real implementation of a concrete class. This can be achieved via partial mocks.
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#16

Categories