Mockito initialize list of mock object behaviour - java

I ran into this problem when writing unit tests and took me a while to fix it. But still, I would like to understand what caused the discrepant behaviour:
1) Using Arrays.asList()
#Mock SomeClass obj;
List<SomeClass> list = Arrays.asList(obj);
This method doesn't work. It creates a list of size 1, with a null obj inside.
2) Adding mock during setup
#Mock SomeClass obj;
List<SomeClass> list = new ArrayList<>();
...
#Before
public void setup() {
list.add(obj);
}
This method works.
I'm just curious are the differences between the two methods, which might have caused one method to work but not the other?

The difference is based on the fact that the annotation #Mock has context. What I mean is: just putting an annotation somewhere into your source code isn't enough. You have to understand how exactly the annotation works.
And this mockito annotation is based on the various phases that the Junit framework relies on. The #Before method is executed every time before another #Test method gets executed.
So in your first snippet, that code gets run once, initially when the test class itself gets initialized. And at that point, the #Mock annotation hasn't done its magic. Therefore that code simply adds a null to your list.
So basically there is a misconception on your end. You assume that there is only the scope of the annotation that matters. But things are more complicated. This annotation relies on specific temporal aspects of the underlying framework.
The real answer is: whenever you encounter annotations, you have to study their documentation extremely carefully, as they are much more than just some Java language keyword.

Related

How do I get Mockito mocks to cause a failure when unexpected calls are made?

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.

Mockito, mocking a constructor within a method of a class

Currently trying to write unit tests for a complicated system that uses a constructor within one of its method that takes itself as the parameter to inject into a database context and retrieve the correct object from the correct environment.
Trying to use Mockito to emulate this, and make it return a test object instead of it going to try and find it from the database; but i'm stumped as to how to make it work with traditional techniques and #InjectMocks + #Mock annotations.
The essence of the code is below:
public FooService{
public String fooFindObject(FooDefinition fooDef) throws FooDefinitionException{
FooFinder theFooFinders = new FooFinder(this);
Foo fooObj = theFooFinders.findFoo(fooDef);
//Logic to be tested inside here that will throw exception upon bad foo definitions
return fooObj.trackingId();
}
How could I mock this FooFinder object and make it return my own testing foo object so I can test the definition obj. Mockito is being used, and the possiblity of rewriting this code to use get/setters of the FooFinder obj is not allowed - it's not my code and I'm just there to test it.
There is a library that extends upon Mockito: PowerMockito.
It allows you to do quite some more hacking than the usual Mockito. It's pretty sweet, but the thing is, if you need PowerMockito, your design usually smells.
I would definetely refactor your design. But if you can't do this for any reason, please take a look at constructor mocking with PowerMockito:
http://benkiefer.com/blog/2013/04/23/powermockito-constructor-mocking/

When to use when() in Mocktio

I am writing unit tests with JUnit and Mockito. Let's say I have following test class:
#Mock(name="myService")
private myServiceClass myService;
#InjectMocks
private myClassIWantToTest classUnderTest;
final myModelClass myModel = new myModelClass();
#Before
private void setUp(){
MockitoAnnotiations.initMocks(this);
}
#Test
private void testSomething(){
myModel.setCode("someCode");
final MyDataClass myData = new MyDataClass();
myData.setCode("someCode");
doReturn("someCode").when(myModel.getCode());
doReturn(myModel).when(myService.getModelByCode("someCode"));
assertEquals(classUnderTest.getDataByCode(eq("someCode")), myData);
verify(myService.getModelByCode(eq("someCode")), atLeastOnce());
}
The method getDataByCode from my classUnderTest converts the Model into Data and it should have the same code. What is a bit blurry to me is that unit tests should encapsule the classUnderTest from all dependencies. But now I have a problem. I use the setter methods myData and myModel to set a value. The thing is I put a DoReturn in there for myModel, but the problem is, that it's not a injected Mock. The method I try to test unfortunately doesn't have a field, it initializes this inside the method, so I can't really address it.
And the main thing is, when the setter of for example myModel doesn't work anymore or so, my test as shown above, wouldn't work anymore. I guess I have three questions:
How hard do I need to isolate the test class? Don't I need to use the setters for the assertEquals?
Is there another way to deal with objects, which are initialized inside a method I want to test? What is the best way to approach such a matter?
Also, what would be a good pattern for structuring this? I currently initialize my expected myData result inside a test method. The thing is that this is a rather short and easy example, but I have classes where I have tons of objects and methods.
Sounds like your main problem is the design of the class you want to test. But a few things before:
myModel.setCode("someCode");
doReturn("someCode").when(myModel.getCode());
This doesn't make sense. It's not a mock, so do...when doesn't make sense here. And if it was a mock, calling the setter would be useless.
assertEquals(classUnderTest.getDataByCode(eq("someCode")), myData);
Also strange. You want to call getDataByCode, why the eq? Do it. Call it. Write:
assertEquals(classUnderTest.getDataByCode("someCode"), myData);
Mockito-Matchers are good when you want to verify something but normally you don't use them as parameters for real method calls.
verify(myService.getModelByCode(eq("someCode")), atLeastOnce());
Does this code really compile? Shouldn't it be ...
verify(myService, atLeastOnce()).getModelByCode(eq("someCode"));
So, it would be a good idea to actually isolate your unit tests as far as you can. The less external problems you are inviting into your test, the better the test can be.
The method I try to test unfortunately doesn't have a field, it
initializes this inside the method, so I can't really address it.
This simply sounds like a code smell, but without the actual code in question, it's hard to say...

Reuse expectations block several times in JMockit

I am writing test cases for a liferay portal in which I want to mock ActionRequest, ThemeDisplay kind of objects. I have tried with writing expectations in each test method.
Now I want to generalize the approach by creating a BaseTest class which provides me all expectations needed for each method so that I don't have to write it again in the all test classes.
For one class I have tried by writing expectations in #Before method. How can I use same in different classes?
For example I want to do following in several classes:
#Before
public void setUp() {
// All expectations which are required by each test methods
new Expectations() {{
themeDisplay.getPermissionChecker();
returns(permissionChecker);
actionRequest.getParameter("userId");
returns("111");
actionRequest.getParameter("userName");
returns("User1");
}};
}
Also is there a way to provide that whenever I call actionRequest.getParameter() it may return the specific value which I provide?
Any help will be appreciated.
Generally, what you want is to create named Expectations and Verifications subclasses to be reused from multiple test classes. Examples can be found in the documentation.
Note that mocked instances have to be passed in, when instantiating said subclasses.
Methods like getPermissionChecker(), however, usually don't need to be explicitly recorded, since a cascaded instance is going to be automatically returned as needed.
Mocking methods like getParameter, though, hints that perhaps it would be better to use real objects rather than mocks. Mocking isn't really meant for simple "getters", and this often indicates that you may be mocking too much.

What is the difference between Mockito.mock(SomeClass) and the #Mock annotation?

What is the difference between Mockito.mock(Class<T> classToMock) method and the #Mock annotation?
Are they the same?
For Example, is this:
private TestClass test = Mockito.mock(TestClass.class);
the same as:
#Mock
private TestClass test;
They both achieve the same result. Using an annotation (#Mock) is usually considered "cleaner", as you don't fill up your code with boilerplate assignments that all look the same.
Note that in order to use the #Mock annotation, your test class should be annotated with #RunWith(MockitoJUnitRunner.class) or contain a call to MockitoAnnotations.initMocks(this) in its #Before method.
The difference is in the lines of code you need to write :) :) :)
Seriously though, using the annotations has the exact same effect as using the Mockito.mock.
To quote the documentation of MockitoAnnotations the use of annotations has the following benefits:
Allows shorthand creation of objects required for testing.
Minimizes repetitive mock creation code.
Makes the test class more readable.
Makes the verification error easier to read because field name is
used to identify the mock.
The javadoc for MockitoAnnotations is here
There are two significant advantages to using the annotation.
A mock created with #Mock can be injected into the class you're testing, using the #InjectMocks annotation. This is a powerful technique that can make testing significantly easier. It just won't work with mocks created by the mock method.
If you have any errors involving your mock, the name of the mock will appear in the message. If you've used #Mock, then this name will just be the name of the field. This makes it really easy to find the problem mock.
Of course, in addition to these two important advantages, most people find the #Mock notation much more readable, and it does cut down on the amount of code. I see no reason not to use it.
They both are considered same and achieve the same thing but I'd prefer the second one:
#Mock is an annotation which:
Minimizes repetitive mock creation code.
Makes the test class more readable.
Allows shorthand creation of objects required for testing.
The answer of the question is one big mistake.
We just solved some problems caused by Mockito.mock(Your.class) as a field.
We had few #Test methods. The 4th method was throwing an exception with 'thenThrow(ex)'. All of the #Test methods after it was failing and the reason was the exception thrown. They were sharing the mocked instance and the 'when' condition. After we changed from
TestClass testInstance = Mockito.mock(TestClass.class);
to
#Mock
TestClass testInstance;
everything started to work as expected. So Mockito.mock is creating a shared mock between the test methods, and #Mock does not.
In Junit5, use
#ExtendWith(MockitoExtension.class)

Categories

Resources