EasyMock void method - java

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

Related

Junit Testing a method that call rest api

Here is the situation, I have a rest-client application that do all the rest calls. Eg. I can call the api class at other application and use it.
API api = new API();
api.setPath(....)
api.idget(...) something
So right now, I need to write Junit Test for my current method that call the api and get the id from the api.idget(String num) and use the id to do something else.
How should I test this method?
I have tried to use Mockito mock to mock the API
#Mock
API api;
Mockito.when(api.idget(.....).thenReturn(something)
I am so confused how I should test this method. By using mock method, I get the error on when() requires an argument that has to be a method call on mock.
I am sorry I cannot provide actual code. Anything would help.
you are correct. You need to use Mockito.when()
you need to call the correct method on Mockito.when
if you can provide the whole example, we can tell you what to do, right now, the only guess is, you are calling your method without arguments
Mockito.when(api.idget("5")).thenReturn(something)
please note the closing bracket ')' after the idget call - you are missing it in your example

Unwanted mock with mockito

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();

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.

JMockit Partial mock - All methods except one

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.

Mockito: is it possible to combine mock with a method name to create a methodCall inside a when() call?

my first question on StackOverflow. I'd like to be able to do something like:
SomeClass mock = mock(SomeClass.class);
String methodName = "someMethod"; OR Method method = ...someMethod...
Both of these things (the mock and the method) would combine to do the following:
when(mock.someMethod()).thenReturn(null);
Of course, the 'null' value will be changed accordingly for my needs, but I am trying to determine two things:
1) Is it even possible to do something like this in Java? This = combining a class object and a method into a methodCall.
2) How do I do such a thing?
I've researched this endlessly and I can't find anything. The problem is that even if this works with a regular class and a regular method (someClass and someMethod would come together to do someClass.someMethod()), keep in mind that this has to work with a mock object for use inside a when() call.
ANSWERED: when(method.invoke(mock)).thenReturn("Hello world."); is the correct syntax and reflection indeed does work inside a when() call. Thanks Kevin Welker!
Since you basically asked me to repost my comment, modified by your response, as an answer, here it is:
Try using reflection as in:
when(method.invoke(mock)).thenReturn("Hello world.");
although, I'm not sure how this is working for you, since you cannot mock/spy class Method (it is final). Mockito's when() only works on mocks or spies. If this is really working for you, can you post a little more detail?
If it doesn't work, you can -- as I suggested in my comment in the OP -- go the CGLib route and bypass Mockito. It's really not that difficult as it looks at first. In my OSS project Funcito (not a mocking framework), I stripped down a lot of the Mockito CGLib proxying code and rewrote it for my needs. It gives a much simpler view into the world of proxying classes, and intercepting method calls.
ADDITIONAL RESPONSE TO COMMENTS
I see how this is working for you, but I am not sure you really understand how it is working. The reason this might matter is because future changes to the way Mockito itself works could render your solution broken in the future. In essence, the reason it works is almost accidental, but yes it will work.
The way that when() is supposed to work is that what happens in between the parentheses is a method call on a previously created Mockito-generated mock or spy, which is just a fancy proxy of a class, rather than a real instance of the class. The proxies have special logic that intercepts the fake proxied method call and basically add that to a list of registered proxy-method invocations (it is stored in something called an IOngoingStubbing or something like that) for later use. Since Java evaluates parameters before invoking a method, this guarantees that the proxied method call gets registered/remembered before the when() method is actually executed. What the when() does is pops off this IOngoingStubbing, which then becomes the object on which thenReturns() is called.
You are not using this "correctly" but it still works for you. How? Well, all that needs to happen is that a method on the proxy needs to be called in order to be registered in a IOngoingStubbing before when() gets executed. You are not directly invoking a method on a proxy, but you are indirectly invoking a method on a proxy by passing the proxy to Method.invoke(). Hence the criteria is satisfied, and when() already has a proxy-method-call registered in an IOngoingStubbing.
You can see the same kind of "accidental" happiness in the following code, which appears at first to make no sense until you realize how Mockito works:
#Test
public void testSomething() throws Exception {
List listMock = mock(List.class);
Method m = List.class.getDeclaredMethod("get", int.class);
m.invoke(listMock, Mockito.anyInt());
when(null).thenReturn("Hello World"); // Huh? passing null?
assertEquals("Hello World", listMock.get(0)); // works!
}
The above test actually passes! Even though the argument to when is null, what counts is that the proxy (i.e., mock) instance had the correct method invoked on it prior to the when statement being invoked.
While it is unlikely that Mockito will change the basic way things work under the covers, there is still the potential for this to break for you sometime in the future. Like I said, it is more or less a happy accident that it works. As long as you understand the way it works and the risk involved, more power to you.
I think, adding a new method after class initialization is not possible as long as the method is not specified in the interface or class provided to Mockito. You would change the class signature after initialization and this is something which is not possible.
For stub method calls have a look to: http://code.google.com/p/mockito/. There is a sample on stub method calls.
If you want to get dynamic answers, not static ones, you should not use Mockito. Use a fake object or a stub to get you behavior for testing. See: http://martinfowler.com/articles/mocksArentStubs.html for details on this issue.

Categories

Resources