Mockito when/then not returning expected value - java

I'm trying to stub this getKeyFromStream method, using the 'any' matchers. I've tried being more explicit and less explicit (anyObject()), but it seems like no matter what I try, this stub will not return the fooKey in my unit test.
I'm wondering if it is because it is protected or there is something else I'm missing or doing incorrectly. I have other when/then statements throughout the tests that are working but for some reason here, it is not.
Note: The getKeyFromStream generally uses a byteArrayInputStream, but I'm trying to match it with an InputStream, I've tried both to no avail.
public class FooKeyRetriever() //Mocked this guy
{
public FooKey getKey(String keyName) throws KeyException {
return getKeyFromStream(getKeyStream(keyName, false), keyName);
}
//Stubbed this method to return a key object which has been mocked
protected FooKey getKeyFromStream(InputStream keyStream, String keyName){
//Some code
return fooKey;
}
}
Unit Test
#Mock
private FooKeyRetriever mockKeyRetriever;
#Mock
private FooKey fooKey;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testGetFooKey() throws Exception {
when(foo.getKeyFromStream(any(InputStream.class),any(String.class))).thenReturn(fooKey);
FooKey fooKey = mockKeyRetriever.getKey("irrelevant_key");
assertNotNull(fooKey);
}

The problem with your unit-test is, that you are trying to mock a method of your actual class which you want to test but you can't actually invoke a mock method as this will return null unless you declare a mocked return value on that invoked method. Usually, you only mock external dependencies.
There are actually two ways to create test-objects: mock and spy. The primer one will create a new object based on the class you provided which has internal state null and also return null on every invoked method. That's why you need to define certain return values for method invocations. spy on the other hand creates a real object and intercepts method invocations if "mock definitions" are defined for certain methods.
Mockito and PowerMock provide two ways of defining your mocked methods:
// method 1
when(mockedObject.methodToMock(any(Param1.class), any(Param2.class),...)
.thenReturn(answer);
when(mockedObject, method(Dependency.class, "methodToMock", Parameter1.class, Parameter2.class, ...)
.thenReturn(answer);
or
// method 2
doReturn(answer).when(mockedObject).methodToMock(param1, param2);
The difference is, that the method 1 will execute the methods implementation while the later one won't. This is important if you deal with spy objects as you sometimes don't want to execute the real code inside the invoked method but instead just replace the code or return a predefined value!
Although Mockito and PowerMock provide a doCallRealMethod() which you can define instead of doReturn(...) or doThrow(...), this will invoke and execute the code within your real object and ignores any mocked method return statements. Though, this is not that useful in your case where you want to mock a method of your class under test.
A method implementation can be "overwritten" by
doAnswer(Answer<T>() {
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
...
}
)
where you simply can declare what the logic of the invoked method should be. You can utilize this to return the mock result of the protected method therefore like this:
import static org.hamcrest.core.IsSame.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import java.io.InputStream;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class FooKeyRetrieverTest {
#Test
public void testGetFooKey() throws Exception {
// Arrange
final FooKeyRetriever sut = spy(new FooKeyRetriever());
FooKey mockedKey = mock(FooKey.class);
doReturn(mockedKey)
.when(sut).getKeyFromStream(any(InputStream.class), anyString());
doAnswer(new Answer<FooKey>() {
public FooKey answer(InvocationOnMock invocation) throws Throwable {
return sut.getKeyFromStream(null, "");
}
}).when(sut).getKey(anyString());
// Act
FooKey ret = sut.getKey("test");
// Assert
assertThat(ret, sameInstance(mockedKey));
}
}
The code above works, however note that this has the same semantic as simply declaring a return value for the getKey(...) as
doReturn(mockedKey).when(sut).getKey(anyString());
Trying to modify only getKeyFromStream(...) with something like this:
doReturn(mockedKey)
.when(sut).getKeyFromStream(any(InputStream.class), anyString());
without modifying getKey(...) of your System-Under-Test (SUT) won't achieve anything as the real code of getKey(...) would be executed. If you however mock the sut-object, you could not invoke the method in your // Act section as this would return null. If you try
doCallRealMethod().when(sut).getKey(anyString());
on a mock object, the real method woulb be called and as mentiond beforehand, this would also invoke the real implementations of getKeyFromStream(...) and getKeyStream(...) regardless what you specified as mock-method.
As you probably can see by yourself, mocking methods of your actual class under test is not that useful and puts more burden to you than it provides any good. Therefore, it's up to you or your enterprise' policy if you want or need to test private/protected methods at all or if you stick to testing only the public API (which I would recommend). You also have the possibility to refactor your code in order to improve testability although the primary intent of refactoring should be to improve the overall design of your code.

Related

Mockito mocked object passed to child class not being used in super

I am trying to mock authentication and pass the mocked object while instantiating the child class
GoogleOAuthService mockGoogleOAuthService = Mockito.mock(GoogleOAuthService.class);
mockGoogleOAuthService = Mockito.spy(mockGoogleOAuthService);
GoogleCredentials mockGoogleCredentials = Mockito.mock(GoogleCredentials.class);
mockGoogleCredentials = Mockito.spy(mockGoogleCredentials);
Mockito.when(mockGoogleOAuthService.authenticateServiceAccount(secretJson, SERVICE_ACCOUNT_SCOPES)).thenReturn(mockGoogleCredentials);
final HotelViewTpaReportService hotelViewTpaReportService =
new HotelViewTpaReportService(mockGoogleOAuthService, dr);
Where the constructor of HotelViewTpaReportService calls super i.e public HotelViewTpaReportService(GoogleOAuthService googleOAuthService, DownloadRequest downloadRequest) throws Exception { super(googleOAuthService, downloadRequest);
And super class constructor then tries to authenticate googleOAuthService.authenticateServiceAccount. It should at this point return the mocked mockGoogleCredentials since we have written Mockito.when(mockGoogleOAuthService.authenticateServiceAccount(secretJson, SERVICE_ACCOUNT_SCOPES)).thenReturn(mockGoogleCredentials);. But it doesn't and tries authenticating.
// Super Class Constructor
public AbstractTpaReportService(GoogleOAuthService googleOAuthService, DownloadRequest downloadRequest) throws Exception {
this.downloadRequest = downloadRequest;
this.tpaReportConfig = new TPAReportConfig(downloadRequest);
final byte[] secretJson = Base64.getDecoder().decode(getRequiredOption(downloadRequest, "secretJson"));
this.googleCredentials = googleOAuthService.authenticateServiceAccount(secretJson, SERVICE_ACCOUNT_SCOPES);
}
I am fairly new to Java , having migrated from python and nodejs.
Any help is appreciated.
In Mockito there exist different types of mock/stub objects:
Mockito's mocking objects
The tutorial on Baeldung: Mockito - Using Spies, 5. Mock vs Spy, differentiates the two briefly:
Mock: no behavior object, mostly returning null, empty or false
When Mockito creates a mock – it does so from the Class of a Type, not from an actual instance. The mock simply creates a bare-bones shell instance of the Class, entirely instrumented to track interactions with it.
Spy: object using existing behavior, mainly for verification
On the other hand, the spy will wrap an existing instance. It will still behave in the same way as the normal instance – the only difference is that it will also be instrumented to track all the interactions with it.
Use only Mock
There are a few things, you should do different & simpler:
You have already created Mock objects. Don't overwrite them with Spy objects.
Use any(), better typed ArgumentMatchers.any(Your.class) or similar as argument-matcher when defining the mocked return
// Arrange
GoogleOAuthService mockAuthService = Mockito.mock(GoogleOAuthService.class);
// mockGoogleOAuthService = Mockito.spy(mockGoogleOAuthService);
GoogleCredentials mockCredentials = Mockito.mock(GoogleCredentials.class);
// mockGoogleCredentials = Mockito.spy(mockGoogleCredentials);
// defining a mocked response, using `any()` as argument-matcher
Mockito.when(mockService.authenticateServiceAccount(any(), any()).thenReturn(mockCredentials);
// injecting the mock
final HotelViewTpaReportService hotelViewTpaReportService =
new HotelViewTpaReportService(mockAuthService, dr);
// Act
Advanced Mockito usage
Since using mocks should simplify your test code, there are even more elegant or ideomatic ways using Mockito (in JUnit-) tests - compare it to "pythonic":
use annotations (#Mock, #Spy, #InjectMocks) to declare & instantiate plus inject mocks
use static imports to shorten usage of Mockito's helper-methods in most readable way
Your code could look like:
// import some useful static methods
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
class MyTest {
// first creating the mocks
#Mock
final GoogleOAuthService mockAuthService;
#Mock
final GoogleCredentials mockCredentials
// then injecting the mocks
#InjectMocks
final HotelViewTpaReportService hotelViewTpaReportService;
#BeforeEach
public void beforeEach() {
MockitoAnnotations.initMocks(this);
// could also define mock-behavior here, using `when(mockedObject. ..)`
}
#Test
public void testAuthentication() {
// Arrange
// defining a mocked response specific for your test
when(mockService.authenticateServiceAccount(any(), any()).thenReturn(mockCredentials);
// Act
// ... your code here
// Assert
// ... your code here
}
See also:
Creating Mocks and Spies in Mockito with Code Examples
java - ArgumentMatchers.any() versus the other matchers in Mockito 2 - Stack Overflow
java - Finding import static statements for Mockito constructs

Testing lazy initialization by j.u.f.Supplier with Mockito

I have a class Sut with lazy initialization implemented using java.util.function.Supplier. In fact it's more complicated that the code below, but this is the simplest form that Mockito cannot test. The test below throws an error Wanted but not invoked ... However, there were other interactions with this mock. Why doesn't Mockito count the invocation of create? The code flow actually enters create(); I checked that with debugger.
import java.util.function.Supplier;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class TestTimes {
#Test
public void testCreateOnlyOnce() {
Sut sut = spy(new Sut());
sut.getData();
sut.getData();
sut.getData();
verify(sut, times(1)).create();
}
private static class Sut {
Supplier<Object> data = this::create;
void getData() {
data.get();
}
Object create() {
return new Object();
}
}
}
First of all, thanks for the well written question.
I have tested your code myself and seen the error you mentioned. Although, I have changed your code a little bit while debugging... Take a look:
#Test
public void testCreateOnlyOnce() {
Sut sut = spy(new Sut());
sut.getData();
sut.getData();
sut.getData();
verify(sut, times(1)).create();
}
private static class Sut {
private Supplier<Object> data;
// Added de data object initialization on the constructor to help debugging.
public Sut() {
this.data = this::create;
}
void getData() {
data.get();
}
Object create() {
return new Object();
}
}
What I found out while debugging:
The Sut class constructor is being called correctly inside the spy(new Sut()) clause, but the create() method is not being called there.
Every time sut.getData() is called, the create() method is also called. What made me conclude, finally that:
On the constructor, all that this::create did was telling java that, whenever it needs to retrieve the Object from the supplier, that Object will be retrieved from the create() method. And, the create() method being called by the supplier is from a class instance different from what Mockito is spying.
That explains why you cannot track it with verify.
EDIT: From my research, that is actually the desired behavior of the Supplier. It just creates an interface that has a get() method that calls whatever noArgs method you declared on the method reference. Take a look at this on "Instantiate Supplier Using Method Reference".
I want to add a little to Gabriel Pimentas excellent answer. The reason why this works as it does is that mockito creates shallow copies of the spy new Sut() and your Supplier refers to the compiled lambda method inside the original Sut instance and not the spy instance.
See also this question and the mockito documentation.
When you debug your code, you can see how this works:
Sut sut = spy(new Sut()); is now a mocked/spied subclass of Sut as the instance TestTimes$Sut$MockitoMock$1381634547#5b202a3a. Now, all fields from the original new Sut() are shallow-copied, including the Supplier<Object> data. Looking at this field inside the spy, we can see that it is an instance of TestTimes$Sut$$Lambda$1/510109769#1ecee32c, i.e. pointing to a lambda inside the original Sut. When we set a breakpoint inside the create method, we can further observe that this points to TestTimes$Sut#232a7d73, i.e. the original Sut and not the spied instance.
EDIT: Even though this MCVE probably does not resemble your actual code, the following solutions come to mind:
Inject the Supplier into your Sut (either during construction or as a parameter to getData.
Create the supplier lazily within your getData method (so that it points to the mockito-instance)
Don't use a Supplier but just call create directly if the Supplier is not passed from the outside

Unit Testing Java Code - Mocking a non-static method of a different class

public class First {
public First(){
}
public String doSecond(){
Second second = new Second();
return second.doJob();
}
}
class Second {
public String doJob(){
return "Do Something";
}
}
Here I want to test the method "doSecond()" of class "First". For the same, I want to mock the method "doJob" of class "Second".
I know that I can create a mocked instance of class "Second" using the code below.
Second sec = mock(Second.class);
when(sec.doJob()).thenReturn("Stubbed Second");
But I cannot relate this mocked instance with class "First" as of the current code.
Without refactoring the source code, is there any way by which i can achieve the requirement.
Please help.
Take a look at powermock's ability to intercept calls to new and return mocks instead
https://code.google.com/p/powermock/wiki/MockConstructor
This doesn't require changing any sourcecode.
here's the test code where we actually return a mock when First.doSecond() calls new Second()
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class TestFirst {
#Test
public void mockSecond() throws Exception{
Second mock = PowerMockito.mock(Second.class);
PowerMockito.whenNew(Second.class).withNoArguments().thenReturn(mock);
PowerMockito.when(mock.doSecond()).thenReturn("from mock");
First first = new First();
assertEquals("from mock", first.doSecond());
}
}
It's tricky to mock an instance that you create inside of a method, but it's possible.
Using PowerMock, you can accomplish this with the PowerMock.expectNew() method:
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class StackOverflowTest {
#Test
public void testFirst() throws Exception {
Second secondMock = EasyMock.createMock(Second.class);
PowerMock.expectNew(Second.class).andReturn(secondMock);
expect(secondMock.doSecond()).andReturn("Mocked!!!");
PowerMock.replay(secondMock, Second.class);
String actual = new First().doSecond();
PowerMock.verify(secondMock, Second.class);
assertThat(actual, equalTo("Mocked!!!"));
}
}
Effectively, PowerMock is proxying the creation of the new object and substituting whatever value we want when we invoke doSecond().
So, it's possible. However, this is a terrible practice to get into.
One typically wants to mock objects if they involve an outside concern, such as another layer (i.e. database, validation), or if the desired output is coming from other objects that are injected but are safe enough to consider tested.
If your method is capable of getting or retrieving data from a non-injectable source, you should not want to mock that out.
Considering that your method is simple and straightforward, you should really not need to do any mocks here at all. But if you felt that you were forced to, you could do one of a few things:
Create a factory for the creation of Second, and mock the results of the returning factory object with Mockito.
Pass in an instance of Second to that method, and use Mockito as the mock instance.
Declare it as a field (i.e. injected dependency), and use Mockito.
For completeness, here is how the test can be written with the JMockit mocking API, without any refactoring of the original code under test:
public class ExampleTest
{
#Test
public void firstShouldCallSecond(#Mocked final Second secondMock) {
new NonStrictExpectations() {{
secondMock.doJob(); result = "Mocked!!!";
}};
String actual = new First().doSecond();
assertEquals("Mocked!!!", actual);
}
}

Recursively call system while mocking

I've been trying for a while to mock my codes. I'm newby on mocking so lots of things ahead of me to catch. I'm using Powermockito with Mockito and Easymock integration.
I'm having difficulties with mocking a method which is inside the method I wanted to test. So here is an example of the situation I faced:
public class trialClass {
public static int try2(){
return 3;
}
public static int try(int a){
return try2() + a;
}
}
and my test class is:
#RunWith(PowerMockRunner.class)
#PrepareForTest(trial.class)
public class trialTest {
#Before
public void setUp() throws Exception {
PowerMockito.mockStatic(trial.class);
//Here I expect try2() to return 10, even it return 3
PowerMockito.when(trial.try2()).thenReturn(10);
}
#Test
public void testtry() throws Exception {
//After try2() returns 10 recursively inside my try() method,
//I expect result to be 11
Assert.assertEquals(11, trial.try(1));
}
}
This question of mine actually comes from my session variable. My session holds some value and an X method returns that value. All I need is to mock that X method recursively and this question just simulates this case.
Thanks for your help guys.
You need to use Mockito.CALLS_REAL_METHODS
So in your test setup:
PowerMockito.mockStatic(trial.class, CALLS_REAL_METHODS);
EDIT
It occurred to me that you might not want to change to EasyMock instead of Mockito, in that case please disregard...
Partial mocking is the keyword you are after. You don't want to mock everything, just try2(). You should use the PowerMock.mockStaticPartial(Class, String...) method.
Instead of
PowerMockito.mockStatic(trialClass.class);
Use
PowerMock.mockStaticPartial(trialClass.class, "try2");
And then do the actual mocking.
Also note that you defined the clas as trialClass in the code above, but use trial.class in the second code...
Please find an updated version of your TrialTest.java using EasyMock with PowerMock as a solution. PowerMock is easy to configure and does not interfere with most existing jars. You only need a few JARS
powermock-easymock-X.X.X-full.jar
Easymock-X.X.jar
You had some issues with your code that I fixed:
Code Issue: try is a Java keyword so it cannot be used in method name (e.g., try(int a)).
Code Quality: Use Java Object instead of Java primitive (e.g., Use Integer instead of int).
Code Quality: trialClass is a poor Java class name (e.g., Use upperCase for Java class name, don't use the generic word Class unless for educational purposes), maybe Trial.
Here's the updated code:
Trial.java (CUT)
public class Trial {
public static Integer try2() {
return 3;
}
public static Integer try1(int a) {
return try2() + a;
}
}
Working Test Class: TrialTest.java
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(Trial.class)
public class TrialTest {
#Before
public void setUp() throws Exception {
/* Setup */
PowerMock.mockStaticPartial(Trial.class, "try2");
/* Mocks */
// Here I expect try2() to return 10, even it return 3
EasyMock.expect(Trial.try2()).andReturn(10).atLeastOnce();
PowerMock.replayAll();
}
#Test
public void testtry() throws Exception {
// After try2() returns 10 recursively inside my try() method,
// I expect result to be 11
/* Test */
Integer result = Trial.try1(1);
/* Asserts */
PowerMock.verifyAll();
Assert.assertEquals(new Integer(11), result);
}
}

how to setup a call to method of mocked object in mockito without calling the original method itself

mockito-version: 1.9.0
I want to setup a call to a method of a mocked object in mockito without calling the original method itself:
EDIT: this example actually works as expect, i.e. the body method "test()" of does not get executed. However, after further investigation I noticed that the original method had the default visibility modifier and I suspect this to cause problems since after changing it to public (shouldn't this be the same?!) it works as expected.
e.g.
public class TestClass {
public String test() {
System.out.println("test called!");
return "test";
}
}
//in test
TestClass mock = mock(TestClass.class);
when(mock.test()).thenReturn("mock!"); //<-- prints test called here? why? how can I switch it off?
The following, running under Mockito 1.9.0 and JUnit 4.8.2, does not print anything to my console:
import static org.mockito.Mockito.*;
import org.junit.Test;
public class TestNonCall {
public class TestClass {
public String test() {
System.out.println("test called!");
return "test";
}
}
#Test
public void doTest() {
final TestClass mock = mock(TestClass.class);
when(mock.test()).thenReturn("mock!");
}
}
Further, if I put a breakpoint in the test() method it is never hit.
Perhaps post more code? It looks like your example is not complex enough to demonstrate the behaviour you're having problems with.
Also: are you using the latest version of Mockito?
Edit: New Thought: Are You Mocking a Final Method?
If you add a final modifier to the method you are mocking, you get the behaviour you reported.
This is because Mockito does not mock final and static methods. Instead, it delegates the calls to the real implementation.
Might your actual code be attempting to mock a final method?
If so, you can use PowerMock, which is an extension to Mockito that allows mocking final methods.
You would need to add the following annotations to your test case class:
#RunWith(PowerMockRunner.class)
#PrepareForTest(TestClass.class)
public class TestNonCall {
// ...
}
and mock the class using the PowerMock method in your test method:
final TestClass mock = PowerMockito.mock(TestClass.class);
then proceed as usual.

Categories

Resources