Imagine you have method someMethod, how would you go by to test it?
Mockito.when(someClass.someMethod(someParam)).thenReturn(someValue);
var bar = foo() // SUT: ends upp calling someMethod somewhere in the stack
assertThat(bar).isEqualTo(someValue);
vs
Mockito.when(someClass.someMethod(someParam)).thenReturn(someValue);
var bar = foo() // SUT: ends upp calling someMethod somewhere in the stack
verify(someClass, times(1)).someMethod(someParam)
assertThat(bar).isEqualTo(someValue);
It is true that the Mockito.when is "kind of" verifying that someClass.someMethod is being called with the correct arguments. Personally I like the idea of having clear assertions/verifications so that the tests can serve as a form of documentation. I don't like giving my mocks double-responsibilities, I want to keep my mocks just simply as "mocks".
So back to my question.
What is the preferred way, using Mockito.when combined with Mockito.verify or only Mockito.when?
When defines the behaviour of the Mock - declaratively defining the way the mock will respond when methods are invoked with different parameters.
Verify is used to check whether the Mock has been interacted with in various ways.
Here are some URLS to the official Mockito documentation, which I hope will help.
Stubbing - with when
Argument matchers
Verification in order
Making sure interaction(s) never happened
on mock
It's probably worth performing a search for some other examples.
I think this question has been answered in https://stackoverflow.com/a/35301264/473064.
The summary is:
In short, it is considered good Mockito style to explicitly verify only the interactions that can't be implied from well-crafted stubs and postcondition assertions. They may be good calls for otherwise-unmeasurable side effects—logging code, thread executors, ArgumentCaptors, multiple method calls, callback functions—but generally should not be applied to stubbed interactions.
One point that I would add is that sometimes if we want to do a verifyZeroInterations to ensure that no unexpected calls occurred, we would have to first exhaust the known calls by verifying them.
What I usually do is to perform the simplest verify(mock, times(n)).someMethod(anyClass()) as generally as possible without repeating the more specific argument matching that I have already specified in the stubbing, which reduces the duplication as much as possible.
Example:
when(someObject.someMethod(eq("abc"))).thenReturn(someValue);
when(someObject.someMethod(eq("def"))).thenReturn(otherValue);
when(someObject.someMethod(endsWith("suffix"))).thenReturn(anotherValue);
var bar = foo();
assertEquals(expectedBar, bar);
verify(someObject, times(3)).someMethod(anyString());
verifyZeroInteractions(someObject);
Regarding your concern in the comment:
The problem I see is, if a new developer reads the test, they won't know the subbed method is part of the verification process.
The stubbed method is not part of the verification process. It's part of the test case setup, i.e., the Given step.
I think your example might be a little bit misleading. The final output from foo() is usually a transformation of the response from someMethod, i.e., someValue in the example. So if the stubbed method is not called and returned with the correct value, the test would have failed anyway. The said developer would then have to look at the mocking and understand how the test case works.
In the updated example below, there is no need to verify that someMethod is called because if it didn't get called, the assertion would fail.
Mockito.when(someClass.someMethod(someParam)).thenReturn(someValue);
var bar = foo() // SUT: ends upp calling someMethod somewhere in the stack
var expectedValue = // a value depending on `someValue`
assertThat(bar).isEqualTo(expectedValue);
Related
In Mockito when we try to mock a method call, let's say we configure something like this
when(exampleClass.getOutputString(anyString())).thenReturn("output1");
This is all understandable. But my question is what is the reason this thenReturn("output1") method returns an OngoingStrubbing object (same as what when(exampleClass.getOutputString(anyString())) method returns), so that we can do something like this
when(exampleClass.getOutputString(anyString())).thenReturn("output1").thenReturn("output2");
or
when(exampleClass.getOutputString(anyString())).thenReturn("output1").thenThrow(new IllegalArgumentException());
However, both the above cases, when using the mock, it only returns "output1" and that's all the story. Anyone knows, why this chaining feature is present, and what are the uses of it? Kind of same thing applies to doReturn() too.
This means for the first call gives ouput1 and in the second call gives output2, and so on.
when(exampleClass.getOutputString(anyString())).thenReturn("output1").thenReturn("output2");
, The second one you need to reach one condition in the target test class so gives
output1 for the first case but in the second one you want to fail to test for example
try-catch clause or see if the code cover the broken scenarios like exceptions
when(exampleClass.getOutputString(anyString())).thenReturn("output1").thenThrow(new IllegalArgumentException());
I want to check if it returns with same value by using EasyMock's andReturn method. Unfortunately, I come across with "java.lang.IllegalStateException: missing behavior definition for the preceding method call:" when I use EasyMock. I guess it is not possible to test by EasyMock when I try expect method. You will understand question better in the code.
Regards
Alper
Menu menu = EasyMock.createMock(Menu.class)
menu.setName("name");
EasyMock.expect(XmlParseUtility.createLinesToParse(menu).toString()).andReturn(angularLines.toString());
Error Message :
java.lang.IllegalStateException: missing behavior definition for the preceding method call:
Menu.getName()
Usage is: expect(a.foo()).andXXX()
I'm not sure what you wanted to do. To comment one of the comment, EasyMock isn't strict. It is whatever you want.
If you want a Mockito style mock, you will use niceMock.
Then, about your code. I feel like you want to record a call to setName. And then want to make sure the XmlParseUtility.createLinesToParse is working as expected. If I'm right, you want this code:
Menu menu = EasyMock.createNiceMock(Menu.class); // unrecorded methods will return null
menu.setName("name"); // recording a call to setName
replay(menu); // done with recording, going in replaying
assertEquals(angularLines.toString(), XmlParseUtility.createLinesToParse(menu).toString());
verify(menu); // if you want to make sure setName was called
If you are actually trying to stub the static XmlParseUtility.createLinesToParse() method call, then the PowerMock library is what you are looking for.
// instantiate angularLines and menu
PowerMock.mockStatic(XmlParseUtility.class);
EasyMock.expect(XmlParseUtility.createLinesToParse(menu)).andReturn(angularLines);
PowerMock.replay(XmlParseUtility.class);
// invoke test subject
PowerMock.verify(XmlParseUtility.class);
PowerMock also requires that the test be run using their runner and that the class containing the static method be "prepared". For more information, check out their documentation
I have some Mockito behaviors defined and I also have verboseLogging turned on trying to debug why my test is failing. I see in the log that some of the methods are being called with either empty or null parameters, which I am not doing.
DataTypeService dataTypeService = Mockito.mock(DataTypeService.class, withSettings().verboseLogging());
when(dataTypeService.isMultivalued(anyString())).thenReturn(true);
I see this in the log:
dataTypeService.isMultivalued("");
invoked: -> at com.example.rest.service.api.v3.impl.ContentServiceImplTest.getDocumentBySchemaMultiValueTest(ContentServiceImplTest.java:186)
has returned: "false" (java.lang.Boolean)
I see something similar in the log for all of my other when statements as well. They return null instead of what I have in the thenReturn and then it continues and returns the proper item on a second call; however, I am only calling it once. Does defining a when statement, execute it under the covers with no params?
Does defining a when statement, execute it under the covers with no
params?
Kind of. When you use anyString() Mockito puts some internal state and then returns a default value (as stated in the anyString() Javadoc).
After doing that, it calls the mocked object with the default value returned by the Matcher, recording its calling internally to associate with a posterior call to thenReturn or thenThrow. But a mock with no recorded state yet will return a default answer, which is false in your case. So when you verboseLogging() it logs the recording call, printing the first false. But, after the recording, your mock is good to go, returning the expected value in the second and subsequent calls. Therefore, what you're seeing is just Mockito being Mockito, nothing wrong with that. :)
I'm testing a method that call same method (db.getData()) twice. But I must return two different values.
Mockito.when(db.someMethod()).thenReturn(valueOne).thenReturn(valueTwo);
Then I tried out multiple thenReturn().
Unfortunately I'm getting only valueTwo for first & second db.getData() method call.
You are not showing a lot of context but here are some ideas:
make sure db is really a mock object
use the debugger to check if db.someMethod() is called twice as you expect
You can also use thenReturn(valueOne, valueTwo); although that should not make a difference
I suspect that your method is called more than twice and that you are missing the first invocation (which returns valueOne) and only looking at subsequent invocations (which will all return valueTwo).
See the API:
//you can set different behavior for consecutive method calls.
//Last stubbing (e.g: thenReturn("foo")) determines the behavior of further consecutive calls.
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
It's probably you are debugging and when you want to fetch the data of the breakPoint line, you are fetching from mock, so it will return one of it's thenReturn() parameters, so when you resume the test, it will test it with the second parameter.
I recommend you if you doubt it's working properly, one time fetch all thenReturn() items and after that you agree they're OK, start the test again with no tracing thenReturn() items.
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.