Mockito - deep stubbing - java

I am using Mockito to test my classes. I am trying to use Deep stubbing as I didn't a way on injecting a Mock inside another mock object in Mockito.
class MyService{
#Resource
SomeHelper somehelper;
public void create()
{
//....
somehelper.invokeMeth(t);
}
}
class SomeHelper{
#Resource
private WebServiceTemplate webServiceTemplate;
public void invokeMeth(T t)
{
try{
//...
webServiceTemplate.marshalSendAndReceive(t);
}catch (final WebServiceIOException e) {
throw new MyAppException("Service not running");
}
}
}
Now I am trying to Unit test the MyService class's create() method.
I have injected a mock for SomeHelper as follows
#Mock(answer = Answers.RETURNS_DEEP_STUBS)
SomeHelper somehelper;
What I want now is when the invokeMeth() method gets called on the mocked somehelper object it calls the real method in this case.
when(somehelper.invokeMeth(isA(RequestObject.class)))
.thenCallRealMethod();
I was expecting the webServiceTemplate not be null in this case.
However I get a Nullpointer exception when the code tries to execute the line
webServiceTemplate.marshalSendAndReceive(t);
Any clue how I can get access to a deep mock object (i.e. mock within a mock - in this case webserviceTemplete mock inside somehelper mock) and then apply a when condition to throw a WebserviceIOException ?
I want this so that I can test the MyService.create() to check it behaves properly when a WebServiceIOException is thrown down the code.

Yes of course, you are mixing real objects and mocks. Plus using the thenCallRealMethod lloks like a partial mock, it feels wrong here, it's no wonder the javadoc of this method talks about that as well.
I definatelty should stress you than, design wise, having a mock that returns a mock is often a smell. More precisely you are breaking the Demeter Law, or not following the Tell, Don't Ask principle.
Any looking at your code I don't why the code would need to mock WebServiceTemplate. You want to unit test MyService, and I don't see a relationship to WebServiceTemplate. Instead you should focus on the interactions with you helper only. And unit test SomeHelper separately where you'll be able to check the interactions between SomeHelper and WebServiceTemplate.
Here's a little example of how I see the thing:
public void ensure_helper_is_used_to_invoke_a_RequestObject() {
// given a service that has an helper collaborator
... other fixture if necessary
// when
myService.behaviorToTest();
// then
verify(someHelperMock).invokeMeth(isA(RequestObject.class));
}
How those that look for your real use case ?
Hope that helps

Related

Calling real method using Mockito

I am using JDK 11 and spring boot.
I am implementing a rest API and have 3 layers:
controller
service layer
data access layer
I had classes against interfaces at the data-access-layer and did not have any interface at the service layer.
I wrote integration tests using MockMvc, Mockito, etc to exercise the whole path for each point, exposed by the controller. This was not a problem until I tried to introduce the interface at the service layer.
Initially, I mocked only repositories/Daos. So the class structure looked like:
public interface ClientRepo{
......
}
public class ClientRepoImpl implements ClientRepo{
......
}
Mocked the returned data as:
#MockBean
private ClientRepo client;
....
Mockito.when(client.isExistFkUnitId(Mockito.any(UUID.class))).thenReturn(false);
Everything was fine so far.
Now I have introduced interface at the service layer as :
public interface ClientService{
......
}
public class ClientServiceImpl implements ClientService{
......
}
And tried ( Trying to call actual service method):
#MockBean
private ClientService clientService;
....
Mockito.when(clientService.isExistFkUnitId(Mockito.any())).thenCallRealMethod();
But getting nothing but null all the time.
Is there a way to make the real method call keeping the interface?
I think you want to use #Spy annotation instead of #Mock annotation on the field where you want to call the real method. I don't happen to have an example to verify this though.
https://javadoc.io/doc/org.mockito/mockito-core/2.21.0/org/mockito/Spy.html
Then you can do doCallRealMethod().when(clientService.isExistFkUnitId(Mockito.any())).
Because with a spy object you call doReturn/when instead of when/doReturn.
https://javadoc.io/doc/org.mockito/mockito-core/2.21.0/org/mockito/Mockito.html#do_family_methods_stubs
Well, there is no "real" method to call. (Ignoring the fact that default methods in interfaces are a thing nowadays)
Generally, unit tests should be written for the target class in an isolated fashion. Like this, you are always "testing" the "isExistFkUnitId" method as well.
You could set the mock up for specific values:
Mockito.when(clientService.isExistFkUnitId("valueA").thenReturn("answerA");
Mockito.when(clientService.isExistFkUnitId("valueB").thenReturn("answerB");
Anyways... to respond to your actual question:
If possible, you can instantiate the implementation in a way that the desired method is working and call it through the mock:
ClientServiceImpl clientServiceImpl = new ClientServiceImpl(...);
// spaghetti code only for demonstration purposes ;)
Mockito.when(clientService.isExistFkUnitId(Mockito.any())).then(i -> clientServiceImpl.isExistFkUnitId((String) i.getArguments()[0]));
POC test:
#Test
public void testit() {
Myclass myclass = new Myclass();
Myinterface mock = Mockito.mock(Myinterface.class);
Mockito.when(mock.myMethod(Mockito.any())).then(i -> myclass.myMethod((String) i.getArguments()[0]));
assertThat(mock.myMethod(" works")).isEqualTo("yeehaa works");
}
public interface Myinterface {
String myMethod(String params);
}
public static class Myclass implements Myinterface {
#Override
public String myMethod(String params) {
return "yeehaa" + params;
}
}
Not exactly a beautiful solution, but if there is no way around it, it should work.
As you are mocking an interface Mockito doesn't know which implementation are you referring. The only way will be to use the Class.
I was having the same problem. My problem was due to the ClientService having dependencies that were not mocked when I set up the tests in this format. So ClientService had a mock, but if I tried clientService.productService.get() or something of that nature the dependant productService was always null. I solved this using testing reflection:
#MockBean
DependentService mockDependentService
ControllerToTest controllerToTest
#BeforeEach
public void setup() {
mockDependentService = mock(DependentService.class);
controllerToTest = mock(ControllerToTest.class);
ReflectionTestUtils.setField(controllerToTest, "dependantService", mockDependentService);
}
#Test
void test() {
//set up test and other mocks
//be sure to implement the below code that will call the real method that you are wanting to test
when(controllerToTest.methodToTest()).thenCallRealMethod();
//assertions
}
Note that "dependantService" needs to match whatever you have named the instance of the service on your controller. If that doesn't match the reflection will not find it and inject the mock for you.
This approach allows all the methods on the controller to be mocked by default, then you can specifically call out which method you want to use the real one. Then use the reflection to set any dependencies needed with the respective mock objects.
Hope this helps!

Unit test fails because the service is offline

I have a unit test that fails because it indirectly calls a method which is dependent upon a service. But when unit tests are run, the service is offline. I tried using Mockito for mocking the behavior of this service dependent method, but the problem is that this method is a static method in a final class, so Mockito does not work in this case.
I also tried using PowerMock with Mockito, but again as the method is not called directly from the unit test, it does not work. This is the skeleton of my unit test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(FinalClassWithStaticMethod.class)
public class MyObjTestCase {
#Test public void myRandomTest() throws Exception {
PowerMockito.mockStatic(FinalClassWithStaticMethod.class);
MyObj returnObj = new MyObj();
// setup fields for returnObj
...
...
PowerMockito.when(FinalClassWithStaticMethod.staticMethod((AnotherObj)anyObject())).thenReturn(returnObj);
AnotherObj obj = new AnotherObj();
// setup fields for obj...
MyObj mockedObj = FinalClassWithStaticMethod.staticMethod(obj); // This returns the mocked value.
// TestUtil.staticMethod calls another class' method which calls FinalClassWithStaticMethod.staticMethod.
MyObj myObj = TestUtil.staticMethod(obj); // This does not return mocked value.
}
}
My questions:
Are the unit tests even meant for such scenarios?
Is there a way by which I can get this unit test to work without modifying the final class? In case I do have to modify the existing classes, what is the correct way of doing it by minimal effects on the dependent code? Although it is a specific scenario, links to examples that exhibit such refactoring will be great help.
In your case, you should ideally be mocking the service object. The mocking will only work if the method that is calling the service is using the mocked object. If the client for the service can be created and passed to the class calling the service directly from the unit test (setter/constructor) when the object is created in the unit test, then you don't have to make too many changes.
Sample code:
class CallsService {
public CallsService(final ServiceClient client) {
... }
public someMethod() {
client.callService();
}
}
In unit test:
void test() {
ServiceClient mockedClient = mock(ServiceClient.class);
// Setup mocks to return as required
CallsService caller = new CallsService(mockedClient);
}
This way the caller will use the mockedClient in the unit test, and in the actual program it can get a client to the real service.

Why Cannot I use Mock and InjectMocks together?

valid construction:
#InjectMocks
SomeClass sc = mock(SomeClass.class);
Invalid construction:
#InjectMocks
#Mock
SomeClass sc;
I want to inject mocks to another mock. I want to use only annotation style.
Why was in Mockito forbid second construction ?
Update
example:
public class ArrTest {
private SomeClass someClass;
public List<String> foo(){
anotherMethod(); // I suppose that this method works. I want to test it separately.
//logic which I need to test
return someClass.doSmth();// I suppose that this method works. I want to test it separately.
}
public void anotherMethod(){
///...
}
}
public class SomeClass {
public List<String> doSmth(){
return null;
}
}
test:
public class ArrTestTest {
#InjectMocks
ArrTest arrTest = Mockito.mock(ArrTest.class);
#Mock
SomeClass someClass;
#Test
public void fooTest(){
Mockito.when(someClass.doSmth()).thenReturn(new ArrayList<String>());
Mockito.doNothing().when(arrTest).anotherMethod();
System.out.println(arrTest.foo());
}
}
It sounds like you're trying to do something that doesn't really make sense. You shouldn't need to inject any dependencies into your mock since mocks by definition don't have any behaviour until you define it with when(mock.someMethod()).thenAnswer() or some variation.
(except perhaps if you're using a spy(), but you've specifically said you're using a #Mock).
Maybe you could explain your use case and why you're trying to inject dependencies into a mock?
#InjectMocks specifically indicates that the annotated field will NOT contain a mock. Annotating #InjectMocks #Mock is not just unsupported—it's contradictory.
To return stubs wherever possible, use this:
#Mock(answer=Answers.RETURNS_DEEP_STUBS)
YourClass mockYourClassWithDeepStubs;
But heed the official documentation for this Answer:
WARNING: This feature should rarely be required for regular clean code! Leave it for legacy code. Mocking a mock to return a mock, to return a mock, (...), to return something meaningful hints at violation of Law of Demeter or mocking a value object (a well known anti-pattern).
Good quote I've seen one day on the web: every time a mock returns a mock a fairy dies.
A mock doesn't have any real implementation. #InjectMocks would try to find and call setters for whatever mock objects have already been created and pass them in. Mockito "knows" that this is kinda pointless on a mock, since there won't be any way to get the mock objects back out, much less do anything meaningful with them.

NotAMockException while Mockito.verify(Object,VerificationMode.atleast(2))

I am using mockito for mock the unit test cases and am getting the following exception
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type ConsumerImpl and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
verify(mock).someMethod();
verify(mock, times(10)).someMethod();
verify(mock, atLeastOnce()).someMetenter code herehod();
and my code is
MessageConsumer mConsumer = Mockito.mock(MessageConsumer.class);
String data = "new Message for Testing";
Message message = new Message(data.getBytes());
Mockito.when(mConsumer.next(10, TimeUnit.SECONDS)).thenReturn(message);
StringParserTest parserTest = new StringParserTest();
ConsumerImpl<String> consumer = new ConsumerImpl<String>(mConsumer, parserTest);
String mes=Mockito.verify(consumer,VerificationModeFactory.times(3)).consumeMessage(10,TimeUnit.SECONDS);
Please some one help me to solve this problem
Thanks in Advance
SRN
Well, that's exactly what mockito says, you are not passing a mock to verify !
ConsumerImpl<String> consumer = new ConsumerImpl<String>(mConsumer, parserTest);
String mes=Mockito.verify(consumer,VerificationModeFactory.times(3)).consumeMessage(10,TimeUnit.SECONDS);
Plus if you verified a mock why would you want to store the result of the invocation you verify, it wouldn't make sense since the consumer is mocked. Verify is to verify calls on mocked objects that are the collaborators of your unit tested object. Which in your case is not really clear.
Also you never use your mock mConsumer instance.
You should definitely separate your test in 3 phase, one for the fixture, one for the action, and one for the verifications. Use the BDD terminology to achieve that, it augments understanding and readability for the tester and future reader of this code (And Mockito offers them in the API through BDDMockito).
As I don't really get what the code is trying to test from the code you gave, I'll be imagining things. So for example you'll write this kind of code (using import static) :
// given a consumer
MessageConsumer message_consumer = mock(MessageConsumer.class);
String the_message_data = "new Message for Testing";
given(message_consumer.next(10, SECONDS)).willReturn(new Message(the_message_data.getBytes()));
// when calling the client of the customer (which is the unit that is tested)
new MessageProcessor(message_consumer).processAll();
// then verify that consumeMessage is called 3 times
verify(message_consumer, times(3)).consumeMessage(10, SECONDS);
Remember Mockito helps you focus on interactions between objects — as it's the most important notion of object oriented programming — and especially between the tested one and his collaborators that will certainly be mocked.
Usually we mock using #InjectMock and we try to verify a method called from inside the test case method.
Here is one scenario which generally give issue.
public class A{
#Autowired
Service s
public void method1(){
method2();
}
public void method2(){
s.someMethod();
}
}
public class ATest{
#InjectMocks
A a;
public void testM1(){
a.method1();
Mockito.verify(a, Mockito.times(1)).method2();
}
}
This will always give "NoAMockException while Mockito.verify"
instead of that we should use following verification.
public class ATest{
#InjectMocks
A a;
#Mock
Service s
public void testM1(){
a.method1();
Mockito.verify(s, Mockito.times(1)).someMethod();
}
}
Or if we want to verify() method2()
then we have to #Mock class A instead of #InjectMock

Mockito: Mocking "Blackbox" Dependencies

So I have been asked to read up on mocking and BDD for our development team and play around with mocks so as to improve a handful of our existing unit tests (as an experiment).
I have ultimately chosen to go with Mockito for a number of reasons (some outside the scope of my control), but namely because it supports both stubbing and mocking for instances when mocking would not be appropriate.
I have spent all day learning about Mockito, mocking (in general) and BDD. And now I am ready to dig in and start augmenting our unit tests.
So we have a class called WebAdaptor that has a run() method:
public class WebAdaptor {
private Subscriber subscriber;
public void run() {
subscriber = new Subscriber();
subscriber.init();
}
}
Please note: I do not have a way to modify this code (for reasons outside the scope of this question!). Thus I do not have the ability to add a setter method for Subscriber, and thus it can be thought of as an unreachable "blackbox" inside of my WebAdaptor.
I want to write a unit test which incorporates a Mockito mock, and uses that mock to verify that executing WebAdaptor::run() causes Subscriber::init() to be called.
So here's what I've got so far (inside WebAdaptorUnitTest):
#Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor();
// When
adaptor.run();
// Then
verify(mockSubscriber).init();
}
When I run this test, the actual Subscriber::init() method gets executed (I can tell from the console output and seeing files being generated on my local system), not the mockSubscriber, which shouldn't do (or return) anything.
I have checked and re-checked: init is public, is neither static or final, and it returns void. According to the docs, Mockito should have no problem mocking this object.
So it got me thinking: do I need to explictly associate the mockSubscriber with the adaptor? If this is a case, then ordinarily, the following would normally fix it:
adaptor.setSubscriber(mockSubscriber);
But since I cannot add any such setter (please read my note above), I'm at a loss as to how I could force such an association. So, several very-closely-related questions:
Can anyone confirm that I've set the test up correctly (using the Mockito API)?
Is my suspicion about the missing setter correct? (Do I need to associate these objects via a setter?)
If my above suspicion is true, and I can't modify WebAdaptor, are there any circumventions at my dispose?
Thanks in advance!
You need to inject the mock into the class which you are testing. You do not need access to Subscriber. The way mockito and other mocking frameworks help is that you do not need access to objects which you are interacting with. You do however need a way to get mock objects into the class you are testing.
public class WebAdaptor {
public WebAdaptor(Subscriber subscriber) { /* Added a new constructor */
this.subscriber = subscriber;
}
private Subscriber subscriber;
public void run() {
subscriber.init();
}
}
Now you can verify your interactions on the mock, rather than on the real object.
#Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor(mockSubscriber); // Use the new constructor
// When
adaptor.run();
// Then
verify(mockSubscriber).init();
}
If adding the Subscriber to the constructor is not the correct approach, you could also consider using a factory to allow WebAdaptor to instantiate new Subscriber objects from a factory which you control. You could then mock the factory to provider mock Subscribers.
If you don't want to change the production code and still be able to mock the functionality of the Subscriber class you should have a look at PowerMock. It works fine together with Mockito and allows you to mock the creation of new objects.
Subscriber mockSubscriber = mock(Subscriber.class);
whenNew(Subscriber.class).withNoArguments().thenReturn(mockSubscriber);
Further details are explained in the documentation for the PowerMock framework.
There is a way to inject your mock into the class under test without making any modifications to the code. This can be done using the Mockito WhiteBox. This is a very good feature that can be used to inject the dependencies of your Class Under Test from your tests. Following is a simple example on how it works,
#Mock
Subscriber mockSubscriber;
WebAdaptor cut = new WebAdaptor();
#Before
public void setup(){
//sets the internal state of the field in the class under test even if it is private
MockitoAnnotations.initMocks(this);
//Now the whitebox functionality injects the dependent object - mockSubscriber
//into the object which depends on it - cut
Whitebox.setInternalState(cut, "subscriber", mockSubscriber);
}
#Test
public void runShouldInvokeSubscriberInit() {
cut.run();
verify(mockSubscriber).init();
}
Hope this helps :-)
You could have used PowerMock to mock the constructor call without changing the original code:
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(WebAdaptor.class)
public class WebAdaptorTest {
#Test
public void testRunCallsSubscriberInit() {
final Subscriber subscriber = mock(Subscriber.class);
whenNew(Subscriber.class).withNoArguments().thenReturn(subscriber);
new WebAdaptor().run();
verify(subscriber).init();
}
}
You cannot mock the Subscriber using Mockito in your current implementation.
The problem you have is that the Subscriber is constructed and then immediately accessed, Mockito has no ability to replace (or spy) the Subscriber instance after creation but before the init method is called.
public void run() {
subscriber = new Subscriber();
// Mockito would need to jump in here
subscriber.init();
}
David V's answer solves this by adding the Subscriber to the constructor. An alternative that retains the hidden Subscriber construction would be to instantiate the Subscriber in a WebAdapter no-arg constructor and then use reflection to replace that instance before calling the run method.
Your WebAdapter would look like this,
public class WebAdaptor {
private Subscriber subscriber;
public WebAdaptor() {
subscriber = new Subscriber();
}
public void run() {
subscriber.init();
}
}
And you could use ReflectionTestUtils from Springframework's test module to inject dependencies into that private field.
#Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor();
ReflectionTestUtils.setField( adaptor "subscriber", mockSubscriber );
// When
adaptor.run(); // This will call mockSubscriber.init()
// Then
verify(mockSubscriber).init();
}
ReflectionTestUtils is really just a wrapper about Java's reflection, the same could be achieved manually (and much more verbosely) without the Spring dependency.
Mockito's WhiteBox (as Bala suggests) would work here in place of ReflectionTestUtils, it is contained within Mockito's internal package so I shy away from it, YMMV.

Categories

Resources