Before this gets marked as duplicate, I've gone through all topics on SO that I could find and I did not see anything close to what I am trying to achieve.
I'm working on writing Unit tests for several so called 'fluent' interfaces and I am facing difficulties verifying the chain of method calls without making it too complex and unreadable. Perhaps, I thought I was missing out on something and I am just trying to reinvent the wheel. How would I go about that?
Having a mocked object MyQuery mockedQuery, I'd like to achieve the following:
MyQuery nameQueryMock = Mockito.mock(MyQuery.class);
Mockito.doReturn(nameQueryMock).when(mockedQuery)
.name("SPECIFIC NAME");
MyQuery addressQueryMock = Mockito.mock(MyQuery.class);
Mockito.doReturn(addressQueryMock).when(nameQueryMock)
.address("SPECIFIC ADDRESS");
Mockito.doReturn(JOHN_QUERY_RESULT).when(addressQueryMock)
.singleResult();
What I was hoping to do is more like:
Mockito.when(mockedQuery.name("SPECIFIC NAME").address("SPECIFIC ADDRESS").singleResult()).thenReturn(JOHN_QUERY_RESULT);
But I found out that is not how it works. I tried playing around with the Answers provided by Mockito (RETURNS_DEEP_STUBS was one of the things I tried) but I found out it worked only on the last method call of the chain as pointed out in the docs. In my case, I need to return JOHN_QUERY_RESULT only when both the name() method is passed "SPECIFIC NAME" and address() is passed "SPECIFIC ADDRESS".
I expect to be able to achieve this in a more neat way, as my chains include a lot more methods and taking the first approach overloads my tests with a lot of code which I hope to avoid.
What am I missing here?
Update:
Some background:
There's a MyService which provides a createQuery() method that returns a new instance of MyQuery. This service (MyService) is used in a class I am trying to test, this class does some job, but it makes use of (those) queries to retrieve information about something that it has to do. Therefore mocking MyService and Injecting it in the tested class, also using a mocked MyQuery will allow me to test the behavior itself eliminating the internal implementation of MyQuery, just by being able to specify what the return should be on SPECIFIC query searches.
Based on your background info I came up with the following example:
(so that might be totally off base from your real case)
Lets say your TestClass has a method like this
public String someMethod(String name, String address) {
return service.createQuery().name(name).address(address).singleResult();
}
and the test for it would look like that:
#InjectMocks
TestClass testClass;
#Mock
MyService service;
#Test
public void test() {
MyQuery query = Mockito.mock(service);
when(service.createQuery()).thenReturn(query);
Mockito.when(mockedQuery.name("SPECIFIC NAME")
.address("SPECIFIC ADDRESS")
.singleResult())
.thenReturn("JOHN_QUERY_RESULT");
Assert.assertEquals("JOHN_QUERY_RESULT", testClass.someMethod("SPECIFIC NAME", "SPECIFIC ADDRESS"));
}
In my case, I need to return JOHN_QUERY_RESULT only when both the name() method is passed "SPECIFIC NAME" and address() is passed "SPECIFIC ADDRESS".
That part would already be covered by the test, simply by the fact that if the mocks would not match you would get an NullPointerException instead.
Also it sounds like something that isn't relevant for a UnitTest of the TestClass, but instead should be relevant for a UnitTest of MyQuery.
However lets have a look at the test. We can see that every line of the test includes a operation based on a mock.
What have we achieved with that test? Did we test the TestClass?
No. We could have just mocked the whole TestClass instead and return the result directly. And mocking the TestClass is bad.
So my answer to that is: Nothing.
We have verifed that mockito does what is supposed to do, and chaining method calls work, but that is beyond the point of a good test.
What can we do to improve this?
I'd say a test like that is not really cut out for a UnitTest, even less for mocking, instead we should focus on an integration test.
In case MyQuery#singleResult has some 3rd party interactions, for example with a database, then this is something that could be mocked.
However in the end we would still need another Integration-Test for the database interaction. In that case we might be better of by restricting ourselves to only test some Exceptions that are normally to hard to reproduce.
Related
I have a problem with mockito while mocking up the final field of a class can you guys help on that
public class Product{
public final String VALUE= "ABC";
public String someMethod(){
if (!VALUE.equals("ABC")){ ## IF NOT WORKING
//inside if condition
}else{
//inside else condition
}
}
}
//Test Class
#test
public void test_someMethod(){
Product product = Mockito.mock(Product.class,"Product");
Field field = Product.class.getDeclaredField("VALUE");
field.setAccessible(true);
ReflectionUtils.setField(field, product , "XYZ");
}
Now, when running in debug mode this shows me changed value to XYZ but dosen't work with if condition always goes in else block despite shows XYZ in debug mode.
Basically, you are going down the very wrong rabbit hole here. It is not a good idea to throw together so many things.
First of all, Mockito (and all the other mocking frameworks) are intended to be used for behavior, not state. In other words. Albeit your mock object actually has that field, keep in mind: it still is a mock object. You won't find much documentation or tutorials telling you what the mocking framework will do about fields, and field values of mocked objects.
Worse, and the real problem: you do not mock your class under test. You use mocks to gain control over other objects that your code under test is using. Mocking and testing the same object simply does not make (much) sense!
Then: do not use reflection together with "mocking" based unit testing, especially not to "reflect" on mocked objects. As said: these frameworks do whatever they think is necessary, so even if some code works today, there is a realistic chance that a new version of Mockito might change such internals, and cause such code to fail in the future.
Next, note that your code is nonsensical to begin with:
public final String VALUE= "ABC";
public String someMethod(){
if (!VALUE.equals("ABC")){ ## IF NOT WORKING
VALUE is always ABC, so you always end up with if(!true). There is no point in having that if statement in your code then.
So, if you really need such kind of a switch, you could make it a method call, like:
public String someMethod(){
if (reallyDoIt())) ...
with
boolean reallyDoIt() { return ...
The point is: now you could use Mockito's spy concept to test your someMethod() call. By doing so, you can instruct Mockito to "really" call someMethod() but to return a fake answer for reallyDoIt(). For more details, see here for example.
Beyond that, I strongly recommend that you step back and read a good tutorial about Mockito, like the one from vogella. Simply because your code implies that you do not really understand how to use mocking frameworks in unit testing.
Thanks.. for detailed explanation. But for me here limitation is not to change the base code (I.e somemethod()).
I have some mock objects that are probably going to get passed around a bit and might end up being fairly complex.
I'd like to either have Mockito output a log for each call made to a mock or I'd like it to fail whenever an unexpected call is made so I can iterate through those calls and set up appropriate responses.
How can I accomplish this?
The most-idiomatic way of doing this is with verifyNoMoreInteractions, as in Mockito docs #8:
//interactions
mock.doSomething();
mock.doSomethingUnexpected();
//verification
verify(mock).doSomething();
//following will fail because 'doSomethingUnexpected()' is unexpected
verifyNoMoreInteractions(mock);
I say "most-idiomatic" above because that method has its own warning label, which links to the blog post "Should I worry about the unexpected?" by Mockito originator Szczepan Faber.
verifyNoMoreInteractions() is not recommended to use in every test method. verifyNoMoreInteractions() is a handy assertion from the interaction testing toolkit. Use it only when it's relevant. Abusing it leads to overspecified, less maintainable tests.
In short, you should have a very clear reason to check what your dependency is not doing or what your system-under-test is not calling, as opposed to what they are doing and calling. You might use verifyNoMoreInteractions for an RPC object, if you want to avoid unnecessary RPC calls, but not (say) a calculator with no side effects. Even better is to specify your exact requirements with never() or times(int) as parameters to verify.
That said, there are two even-less-idiomatic ways of doing this:
You can take an overall log of calls made using mockingDetails(Object) and iterating through getInvocations(). That should reflectively give you a whole list of the invocations. I have a hard time imagining how this would be useful in a test, but it might be useful in cleaning up a nebulous or poorly-documented existing system.
You can make the mock's default action to throw an exception, which means that if anyone calls something that you haven't stubbed, the test will immediately fail.
// untested pseudocode
YourObject yourObject = Mockito.mock(YourObject.class, withSettings()
.defaultAnswer(invocation -> {
throw new UnsupportedOperationException(invocation.toString());
}));
Sure, that'd work, but you'd not only be violating one of Mockito's core principles (mocks are nice by default, using EasyMock's definition of "nice"), but you'd also force yourself to only stub using doVerb (doReturn, doAnswer, etc) because calls to when(yourObject.doAnything()) would necessarily throw that exception before the call to when would even run.
Developers who are familiar with Mockito would likely say that this exception-prone cure is worse than the disease, and may be useful only for temporarily diagnosing the most tangled legacy code.
I was just asking myself the same question and... The solution using ReturnsSmartNulls will return SmartNulls instead of null... So it is meaningful for non-void methods only right ? What about void methods, the ones having side effects ?
In my opinion, if you want to make sure that your test fails when a method of your mock is called without your explicit behavior definition of it (doXXX(...).when(...) mockito methods) you can initialize your mocks with a custom default answer that will throw an exception, or better... fail your test.
For example you can add the following class inside your test class (or outside if you intend to use it elsewhere, or even use a MockitoConfiguration class as previously mentionned depending on what you want):
static class FailAnswer implements Answer<Object> {
#Override
public Object answer(InvocationOnMock invocation) {
String methodName = invocation.getMethod().getName();
String className = invocation.getMethod().getDeclaringClass().getSimpleName();
return fail(String.format("%s#%s should not have been called", className, methodName));
}
}
Then init your mock with this fake answer in your setUp method :
#BeforeEach
void setUp() {
delegateService = mock(DelegateService.class, new FailAnswer());
classUnderTest = new ClassUnderTest(delegateService);
}
Unfortunately, this solution is not compatible with #Mock annotation which only takes native predefined answers from org.mockito.Answers enum as argument. So that forces you to manually init every mock, spy, captor within the setUp method (RIP MockitoAnnotations.initMocks(this))
Benefit :
you get rid of default behavior of mockito mocks, sometimes hidding unintentionnal uses of mocks for specifics use cases (does is really matter ?)
=> You must define everything you use (inside tests or tests fixtures)
=> you don't have to make verification to make sure your test have not invoked methods it shouldn't have.
Drawbacks :
This is an unusual usage of mockito, so this makes your test less affordable
You give up on MockitoAnnotations feature
As you override mockito default stubbing, you must use the stubbing form do().when() instead of when(...).do(....), the latter providing au type-checking unlike the former.
Warning : This solution doesn't garantee your mock is called, it just garantees that the method you don't stub won't be called. It doesn't come as replacement for counting methods invocations neither.
The best answer I found is to configure Mockito to return SmartNulls.
https://static.javadoc.io/org.mockito/mockito-core/2.6.9/org/mockito/Mockito.html#RETURNS_SMART_NULLS
This implementation can be helpful when working with legacy code. Unstubbed methods often return null. If your code uses the object returned by an unstubbed call you get a NullPointerException. This implementation of Answer returns SmartNull instead of null. SmartNull gives nicer exception message than NPE because it points out the line where unstubbed method was called. You just click on the stack trace.
You can do it by mock or by default (might cause problems with other frameworks like Spring).
Manually
Writer writerMock = mock(Writer.class, RETURNS_SMART_NULLS);
Annotation
#Mock(answer = Answers.RETURNS_SMART_NULLS)
Set as Global Default
Configuration class must be in exactly this package. This might lead to strange failures with Spring.
package org.mockito.configuration;
import org.mockito.internal.stubbing.defaultanswers.ReturnsSmartNulls;
import org.mockito.stubbing.Answer;
public class MockitoConfiguration extends DefaultMockitoConfiguration {
public Answer<Object> getDefaultAnswer() {
return new ReturnsSmartNulls();
}
}
See: https://solidsoft.wordpress.com/2012/07/02/beyond-the-mockito-refcard-part-1-a-better-error-message-on-npe-with-globally-configured-smartnull/
I had problems with SpringBootRepositories and #MockBean when enabling the global default:
java.lang.ClassCastException: org.mockito.codegen.Object$MockitoMock$191495750 cannot be cast to xxx.xxx.MyObject
Example of error output
org.junit.ComparisonFailure: expected:<[DataRecordType{id=null, name='SomeRecord', pathTemplate='SomeTemplate'}]> but was:<[SmartNull returned by this unstubbed method call on a mock: dataRecordTypeRepository bean.getById(1L);]>
If you are trying to track the flow, you can use Mockito verify to check if certain call has been made.
verify(yourMockedObject).yourMethod();
you can also use times to verify if certain call has to be made exactly some number of times.
verify(yourMockedObject, times(4)).yourMethod();
It is not a good practice to make your unit test complex. Try to test only small unit of your code at a time.
I'm trying to fix some existing junit/mockito tests that I've had to alter due to a re-write to use Dao's.
So I have this argument captor :-
ArgumentCaptor<CustomerDao> customerDaoCaptor = ArgumentCaptor.forClass(CustomerDao.class);
and I've used this approach before to get the (customer) object so that I can perform more tests on it. I would usually use it like this :-
verify(customerDao, times(1)).saveOrUpdate(customerDaoCaptor.capture());
so that I can then run tests like :-
Customer customerActual = (Customer) customerDaoCaptor.getAllValues().get(0);
assertEquals("PRE", customerActual.getExistingCustomer());
However in this instance I'm not calling the saveOrUpdate method (that the captor is bound to), but another Dao method that takes a unique key as a parameter that ultimately updates the customer record by using sql - ie it doesnt use the parent object's (Hibernate) saveOrUpdate method.
I know that I can test that its called, eg :-
inOrder.verify(customerDao, times(1)).updateRegisterStatusToCurrentByCustomerNumber(CUSTOMER_NUMBER);
so I'm trying to somehow assign/bind the captor to the 'updateRegisterStatus....' method, but I cant seem to find a way to do it, mainly because that method must take a string param, customer_number.
So in essence I'm trying to do this :-
inOrder.verify(customerDao, times(1)).updateRegisterStatusToCurrentByCustomerNumber(CUSTOMER_NUMBER).customerDaoCaptor.capture()
which obviously doesn't work...
As a lot of googling hasn't helped me, I'm guessing that I'm doing it completely wrong.
Update - #SpaceTrucker
I've tried the following code as you suggested :-
CapturingMatcher<String> capturingMatcher = new CapturingMatcher<String>();
verify(customerDao, times(1)).updateRegisterStatusToCurrentByCustomerNumber(
argThat(
org.hamcrest.Matchers.allOf(capturingMatcher, org.hamcrest.Matchers.notNullValue())
)
);
List<String> values = capturingMatcher.getAllValues();
based on my Dao implementation :-
public void updateRegisterStatusToCurrentByCustomerNumber(String customerNumber)
and it does pass the test successfully, in that it doesn't fail, but it doesnt do everything what I need it to. The ideal goal here is to somehow get an object representing the updated customer object - eg :-
Customer customerActual = (Customer) values.get(0);
assertEquals("value", customerActual.getExistingCustomer());
However the values object is empty and on debugging the test I can confirm that the method in question is being called.
Apologies in advance if there's something trivial that I've missed here, and once again, thanks for all your help!
This problem seems to more difficult than first thought about. See below for more details on this.
The Matcher instance Mockito does need to see has to implement the CapturesArguments interface. So the solution is to implement an AndMatcher that will delegate to its child matchers and implements CapturesArguments. It will delegate to all child matchers that also implement CapturesArguments when CapturesArguments.captureFrom(Object). Please note that CapturesArguments is a Mockito internal interface.
The following solution does not work,
because the Matcher instance Mockito sees, doesn't implement the CapturesArguments interface and therefore won't delegate the argument capturing to the CapturingMatcher.
The ArgumentCaptor uses a CapturingMatcher internally. So you could use Mockito.argThat with a combined matcher that will consist of a CapturingMatcher and any other matcher you like.
For example given the interface
public interface ProductService {
List<Product> getProductsForCategory(Category category);
}
then we can do the following:
import org.hamcrest.Matchers;
// ...
CapturingMatcher<Category> capturingMatcher = new CapturingMatcher<Category>();
Mockito.verify(productService).getProductsForCategory(Mockito.argThat(Matchers.allOf(capturingMatcher, Matchers.notNullValue())));
List<Category> values = capturingMatcher.getAllValues();
You could also implement your own ArgumentCaptor with a capture method that will take an additional matcher instance.
Your question isn't entirely clear, but I'm getting the following points from it:
You have a mock of a CustomerDao.
Your test (indirectly) calls the updateRegisterStatusToCurrentByCustomerNumber() method of this mock, passing a String identifier to it.
updateRegisterStatusToCurrentByCustomerNumber() does something internally to a Customer object.
You want to test things about the Customer object in question.
If these are correct, then you have a fundamental misunderstanding of how mocks work. That internal code that does something to a Customer object? In this test, that code doesn't exist. It's never called. The mock version of CustomerDao responds to your updateRegisterStatusToCurrentByCustomerNumber() call by simply returning what your test setup code told it to, whether that's null, a carefully crafted sample object, or another mock. It never invokes the actual CustomerDao code because the whole point of a mock is to make your test not be dependent on that code, so that bugs in that code don't cascade test failures throughout the dependency tree.
To test the internal behavior of CustomerDao.updateRegisterStatusToCurrentByCustomerNumber(), you will need to create separate tests that directly call CustomerDao methods on a non-mock CustomerDao, with everything else being mocks.
I'm new to JMockit and writing a test for a quite complex class, call it XYZ. In each #Test method, I want to call the corresponding real method of XYZ, but mock all (or sometimes nearly all) other methods, which should by verified afterwards. At the moment my first test method looks like this (I want to mock all methods except "start", so I'm using a regex):
#Test
public void testStart(#Mocked({ "^(start).*" }) XYZ xyz) {
new Expectations() {{
xyz.isValidState(); result = true;
}};
...
}
When I run the test, I get "java.lang.IllegalStateException: Missing invocation to mocked type at this point; please make sure such invocations appear only after the declaration of a suitable mock field or parameter" (at the line where the first expectation is defined) which seems to say that the mocking did not work. Is my regex wrong or this there another problem?
That regex selects the methods that will be mocked. So, isValidState() does not get mocked, as it doesn't match the expression; hence JMockit says there was no mocked invocation at the point the "result" field is used.
There is no way to not mock just a single method in a class while mocking all others, except for using partial mocking with new Expectations(XYZ.class) and then recording expectations on all the methods that should be mocked. This, of course, would be cumbersome. Which is a good thing here, because partial mocking in general is not a feature to be used in "normal" cases; it's only for exceptional situations.
If you want to unit test a class, even a complex one, mocking should be restricted to its dependencies, and even then only those dependencies that you choose or need to regard as external to the unit under test. That said, if a given internally called method in XYZ gets in the way of a clean test, then you can exceptionally choose to "mock it out" through partial mocking; but that would usually mean a single method (or just a few) in class XYZ to be mocked per test.
Lets say we have method to test in class A that calls method from class B. To test it we created mock for B and then verify if it was called. Is verify(...) enough for unit test or I need assert actual result of tested method?
Below is simplified example to clarify my concern:
public class StringWriterATest {
StringWriterB b = mock(StringWriterB.class);
#Test
public void stringWriterATest() {
StringBuffer sb = new StringBuffer();
StringWriterA a = new StringWriterA();
a.stringWriterB=b;
a.append(sb);
ArgumentCaptor<StringBuffer> argument = ArgumentCaptor.forClass(StringBuffer.class);
verify(b).append(argument.capture());
assertEquals("StringWriterA", ((StringBuffer)argument.getValue()).toString());
//do we really need this or above is enough for proper unit test of method a.append(sb);
//assertEquals("StringWriterA_StringWriterB", sb);
}
}
public class StringWriterA {
public StringWriterB stringWriterB;
public void append(StringBuffer sb) {
sb.append("StringWriterA");
stringWriterB.append(sb);
}
}
class StringWriterB {
public void append(StringBuffer sb) {
sb.append("StringWriterB");
}
}
Regards,
Max
There is never a need to mock a return value and verify an object at the same time.
Consider this:
StringWriterA is the class under test. Therefore you'll definitely want to use assertions to verify the behavior of this class. In order to do this, you mock out a dependency, StringWriterB.
You do not want to test StringWriterB in your test of StringWriterA, therefore any assertions of StringWriterB interactions in your test are in the wrong place.
You must assume that StringWriterB is behaving as expected. You either want to verify that StringWriterA called StringWriterB correctly (using verify()) or you want to mock its expected behavior and mock the return values.
If you mock, then the verify is implicit since the mocked return value will not be returned if the method is not called.
In your case, StringWriterA.append() does not return any value, so only a verify is even possible. That StringWriterB.append() also works should have a similar verify test in a stringWriterBTest of its own.
Note: It's nice to be explicit with tests. Since test methods are never called outside of a framework, there is never a need to type them out, so you can have much longer method names than in production code methods. A nice convention is:
<underTest>Should<Expected>[When]<Condition>()
i.e.
stringWriterAShouldAppendConstantAndDelegateToStringWriterB()
stringWriterAShouldThrowNullPointerExceptionWhenNullArgument()
When you have test failures in your build (continuous integration), then you don't have to hunt down what went wrong, the method name appears right by the failure and you can read it to know exactly what behavior must be fixed.
In your example, StringWriterB stores no state and the append method could easily be static. In that case then the call is purely a side effect and does not need to be tested.
However, I suspect your real code is much more complex. If there is a of another object accessing StringWriterB then you maye want to mock it out in case there are unexpected calls to it. You also may want to add the verify of B if you expect it to be expanded in the future -- possibly storing state from the append call and having accessors.
One thing to consider is what the purpose of the call to StringWriterA.append() is. If it's job is to append the string StringWriterAStringWriterB then that is what you should be testing and a mock is not necessary. How StringWriterA accomplishes that task is immaterial. If, however, part of its job is to also call the StringWriterB.append() method then a mock may will be necessary unless you want to test StringWriterB in A's test.
My rule of thumb WRT mocks is to use real objects until the wiring for the objects I'm not directly testing gets too hairy or too brittle. If I feel like a good portion of my tests are in actuality testing other objects then mocks would be a good idea.
First of all try to show somebody the test you wrote. It is hard to read in my opinion. You can't really tell from it what behaviour you are testing. A brief intro for you how to make it a bit more readable can be found here How to Write Clean, Testable Code .
Using argument captors is also a smell. Some examples how to avoid it can be found on this tdd blog.
To answer you question, verify is used to verify interactions between classes. It is used to drive the design of your code. The result (if needed) should be specified by a when or given at the beginning of your test.
Further information how to drive your design with mocks (when, given, verify, ...) and how mocks are different to stubs can be found here: Mocks are not stubs. That example uses JMock not Mockito for defining mocks, but it is very similar (it is about the concepts, not the details of implementation and libraries you use).