Unwanted mock with mockito - java

I'm doing unit tests with jUnit 5 and Mockito. In one test, I had to mock a method. Everything works fine. In another test later I'm invoking the same method but this time I don't want Mockito to do anything. Nevertheless, Mockito returns an unasked null value, which makes my test fail.
I thought it was due to the first test, so I added Mockito.reset(). But it didn't change anything.
Do you understand what's happening behind the scene?
I ran the debug mode to have more info about the object created by Mockito. Among other infos I can read
invocationForStubbing: ecritureComptable.toString();
But I don't know where and when this method is called.
Any help appreciated.
EDIT....
Thank you guys. I edited my post to make it clearer and also because I have now a better idea of what possibly happened:
1/ Before each test, I create a mock of the object DaoProxy and I use the mode RETURNS_DEEP_STUBS, which have mockito mock objects nested in DaoProxy
#BeforeAll
private static void injectMockDao() {
DaoProxy daoProxyMock = mock(DaoProxy.class, Mockito.RETURNS_DEEP_STUBS);
AbstractBusinessManager.configure(null, daoProxyMock, null);
}
2/ For a specific test method, I use :
when(getDaoProxy().getComptabiliteDao().getEcritureComptableByRef(Mockito.anyString())).thenReturn(ecritureBDD);
and reset it after use, hopping that by the next call of the all chain, Mockito won't do anything (but it didn't work) :
reset(getDaoProxy().getComptabiliteDao().getEcritureComptableByRef(Mockito.anyString()));
3/ In another test later, i make a call to
getDaoProxy().getComptabiliteDao().getEcritureComptableByRef()
and Mockito - although unasked - returns a null object.
The input of #Gavin makes me assume this is because of the RETURNS_DEEP_STUBS-Mocking of DaoProxy. Mockito mocks the nested object, but since it has no info on what it should return, it returns the default object value : null. This explains why in this case the reset didn't help.

If your object is marked for mocking with #Mock or you have used the mock method to create it then Mockito will return the default value for the type, which for objects is null.
In the failing test you could try to either provide a mocked value in the usual way, or inject a "real" instance of the object being mocked, I believe it is possible to have Mockito to provide a mocked response on a "real" instance of an object.

If you want to make real method call in the second test then use thenCallRealMethod() in the second test
when(mock.someMethod()).thenCallRealMethod();

Related

Mockito JUnit test on method which throws exception

I have a method inside my service which throws exception for one method call. For example, I have a code like:
void myServiceMethod() {
method1(); // passes
method2(); // passes
method3(); // throws exception
method4(); // passes
method5(); // passes
}
What I want, is to handle this method3 (in real program it is a static method), in some way, so that a program can continue executing further code such as method4 and method5 in this example.
Is it possible in mockito junit test, to return any value instead of exception, or to just skip it?
Your question is actually two:
1: how do I avoid execution the mocked method ?
2: how do I mock static methods?
Here are the answeres:
Mockito provides 2 APIs to configure your mock. The more common (and more readable) for is:
when( mock.mockedMethod() ) .thenReturn(someValue);
The problem her is that the real method is actually executed and just the result is replaced. Usually this is not a problem unless your method throws an (unchecked) exception based on the return values of other (mocked but possibly unconfigured) methods in the same object or tries to access methods on dependencies of the mocked object since they are null so that a NPE is thrown.
One way is to also configure return values for all the other methods in your mocked class. But then you have to "open" your mocked classes API bye raising the visibility of all methods involved above private just for testing. But making such changes just for testing is bad design.
To avoid that you need to use the other form which does not execute the configured method:
doReturn(someValue).when( mock ). mockedMethod();
please mind that the closing brace moved from behind the method call to before the dot separating the mock variable from the method call...
This might also solve your problem with the static method in your dependency in your concrete example.
You stated that the method you want to mock is static in your production code.
The problem here is that you should not use static access in your code in the first place. So the best way is to change your method to an instance method and provide is instance of the class providing your "serviceMethod". Then you can use plain Mockito to create a mock and replace it for testing easily.
Some may argue you can use PowerMock to mock static and/or private methods. While this is technically true I'd consider it a surrender to your bad design...

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.

EasyMock void method

I'm trying to use EasyMock to mock out some database interface so I can test the business logic off a wrapping method. I've been going ok with methods that return by using the following in my setup of my test.
DBMapper dbmapper = EasyMock.createMock(DBMapper.class);
userService.setDBMapper(dbmapper);
then within my actual test I run
EasyMock.expect(dbmapper.getUser(userId1)).andReturn(mockUser1);
EasyMock.replay(dbmapper);
userService.getUser(userId1);
This service then connects to the dbmapper and returns the object (the mapper is injected using setter methods)
These type of mocks seem to work fine. However when I try to run a test for
userService.addUser(newUser1);
This method calls a void method.
dbmapper.createUser(newUser);
It's this method that I'm having problems mocking out.
I've tried the following
EasyMock.expectLastCall();
EasyMock.replay(dbMapper);
userService.addUser(newUser1);
as some other posts/questions etc seem to suggest I get an IlligalStateException: no last call on a mock available
Can anyone point me in the right direction please?
Many Thanks in advance
You're close.
You just need to call the method on your mock before calling expectLastCall()
So you expectation would look like this:
userService.addUser(newUser1);
EasyMock.expectLastCall();
EasyMock.replay(dbMapper);
userService.addUser(newUser1);
This works because the mock object is in Record mode before the call to replay(), so any calls to it will perform default behaviour (return null/do nothing) and will be eligible for replaying when the replay() method is called.
What I like to do to make sure that it is obvious the method call is for an expectation is to put a small comment in front of it like this:
/* expect */ userService.addUser(newUser1);
EasyMock.expectLastCall();
EasyMock.replay(dbMapper);
userService.addUser(newUser1);
This problem does not happens if you use the 'nice' API:
DBMapper dbmapper = EasyMock.createNiceMock(DBMapper.class);
There are two kinds of mock - strict and nice. The strict mock throws Assertion Error in case an unexpected method is called. The nice mock allows unexpected method calls on the mock.
For further details, refer to the official doc - http://easymock.org/user-guide.html#mocking-strict

How to mock a function used in the object constructor (with Mockito)?

I need to write unit tests with Java for an Android application. What I currently need to do is to create an object Picture and use it for some tests. The problem with this object is, that it's constructor has a method call:
public Picture(File imageFile) {
this.filename = imageFile.getName();
this.imageDimension = getImageDimension();
/.../
}
Method getImageDimension() references some other classes, therefore I would prefer for separability to just mock it's result. For mocking, I need to give Mockito a constructor, so it seems to me like a chicken-egg problem.
So, is there a chance to mock a function used in the object constructor with Mockito? If no, how could this situation be solved without changing the original code?
Normally you'd mock the entire object and not just a part of it. But if it's not final, create a subclass of Picture and override the constructor and do your custom thing there. That way you can avoid calling the original constructor and you can test the instance.
If it is final then unit testing it becomes quite hard. If you are not actually unit testing this particular class, you should either mock the picture object entirely or not at all.
BTW, this is why you shouldn't allow your constructors to do work: it results in code that is hard to test & mock. Separating object initializations from your logic is a good thing. Probably what you'd want here is an additional constructor that takes filename and dimensions as constructor args.

unit tests and logging

I have a couple of classes: StateProcessor and State.
I want to write a test for the method StateProcessor.process(State).
The logic of this method is pretty simple, but it contains a lot of logging messages.
logger.info(state.getSourse().toString());
if (state.getTarget() == Target.A) {
logger.info(state.getCreationTime());
service.doSmth(state);
} else {
logger.info(state.getTagret().getName());
service.doOtherStff(state);
}
I don't want to pass the real State instance to the process method because this class is really complicated and it takes a lot of lines of code to build it. So, I want to pass mock object created with Mockito. According to the main logic, I need to mock only getTarget() method. But the execution will fail with NPE at state.getTagret().getName() and at state.getSourse().toString(). But I don't like the idea of mocking all of these methods! They used only for logging. Also I don't want to fix my tests every time when I add some logging messages.
Logging is really useful there, so I don't want to remove it at all. But mocking the methods only for logging looks strange.
How I can solve this issue?
Consider Mocking DEEP. This will result in each method call returning a mock instead of null and prevent the NPEs.
Foo mock = mock(Foo.class, RETURNS_DEEP_STUBS);
What you have there is a classic Law of Demeter violation, which is a textbook case for mocking problems.
As an alternative, consider logging the entire State object in one place--such as before the 'if' block--and overriding the toString() method to output everything you need to see. Then you won't need to dereference each field and mock each method.
You could enclose all your logging calls inside an if (!test) {} block and inject the test attribute.
Or you could enclose them into an if (logger.isInfoEnabled()) {} block and configure logging with info disabled, or inject a mock logger which returns false for isInfoEnabled().
But logging is a key part of your code. So if you really want to test that it won't blow up in production, you should either test for nulls in your production code, or prove that these attributes may never return null, and inject a mock which doesn't return null either.
PS: do you really intend to keep properties named tagret and sourse in your code?

Categories

Resources