Mockito spy not mocking internal call to mocked method - java

I have a class that calls out to a third party system to get data that I want to mock using Mockito. Here is some pseudo-code of how my class is setup.
// class I will be spying
public class SomeService {
// method I want to full test
public List<String> methodA(List<String> list) {
... omitted code ...
// internal call to method in the same class that will be mocked
innerList = methodB(list);
... omitted code ...
}
// method that I want to mock/spy
public List<String> methodB(List<String> list) {
//details omitted since it should be mocked any never called
}
}
Here is my test code. I setup my spy in a BeforeEach method to make sure that Mock is configured. When I directly call the mocked method, everything works as expected. When I call
public class SomeServiceTest{
private SomeService service;
#BeforeEach
public void init() {
service = Mockito.spy(SomeService.class);
// also tried with creating a new object but has same failure conditions
//service = Mockito.spy(new SomeService());
// mocking methodB with answer details omitted to reduce clutter
Mockito.doAnswer(..detail omitted..).when(service).methodB(Mockito.anyList());
}
//testing directly calling mocked method that returns mocked data
#Test
public void testMockedMethod() throws Exception {
List<String> list = //setup details ignored
List<String> results = service.methodB(list);
// follow up asserts work
}
//testing indirectly calling mocked method that call actual method code
#Test
public void testMethodA() throws Exception {
List<String> list = //setup details ignored
// NullPointer in methodB since mocking is ignore
List<String> results = service.methodA(list);
// assertions never tested since NPE was thrown
}
}
Does anyone know why when I directly call the mocked method, it returns the doAnswer; but when I indirectly call from within the mocked/spied object it ignores the fact that the method is mocked and calls the original method?

It should work. It seems to me that the NPE exception is because there are some bugs in your codes which already happen before it really executes the stubbed method . What is the stacktrack that you get ?
On the other hand, you can also add some println just before and after calling the stubbed method to verify the codes is really can execute up to that point :
public List<String> methodA(List<String> list) {
.......
System.out.println("before methodB");
innerList = methodB(list);
System.out.println("after methodB which return " + innerList);
....
}

Related

Mockito.mockConstruction does not return the mocked object

I don't want to use powermock anymore. Because junit5 started mocking static classes. So i am trying to get rid of powermock methods.
As you know, you can create an instance of a class with whenNew keyword. So i decided to use " mockConstruction " . But mockConstruction does not return the mocked object. It doesn't go inside the try block.
This is my BeforeEach method:
#BeforeEach
void setUp() {
partUnlinkService =
spy(new PartVideoUnlinkService(part1, part2,
part3));
}
This is my test method:
#Test
void shouldThrowException() throws Exception {
//given
UrlLinkDto urlLinkDto =
UrlPartLinkDto.builder().callId("333").videoId("5555544").build();
ArgumentCaptor<UrlPartLinkDto> argumentCaptor = ArgumentCaptor.forClass(UrlPartLinkDto.class);
//when
try (MockedConstruction<ObjectMapper> ignoredVariable = mockConstruction(ObjectMapper.class,
(objectMapper, context) -> {
//then
partUnlinkService.unlink(urlLinkDto, false);
verify(partLogCheckService, times(1)).checkForExistingVideo(
urlLinkDto.getVideoId());
verify(objectMapper, times(1)).writeValueAsString(argumentCaptor.capture());
Throwable throwable =
catchThrowable(() -> objectMapper.writeValueAsString(argumentCaptor.capture()));
assertThat(throwable).isInstanceOf(JsonProcessingException.class);
})) {
}
}
Any help would be appreciated.
You can access mocks that were created during the instantiation of your objects via MockedConstruction.constructed() method. It represents a collection of mocks that are created after each constructor's execution. If your object will be instantiated 3 times MockedConstruction<T>.constructed() will return 3 different mock objects for each instantiation.
According to documentation MockedConstruction<T>
Represents a mock of any object construction of the represented type.
Within the scope of the mocked construction, the invocation of any
interceptor will generate a mock which will be prepared as specified
when generating this scope. The mock can also be received via this
instance.
Simple implementation with comments below shows how to get mocks from MockedConstruction and verify them:
public class A {
private final String test;
public A(String test) {
this.test = test;
}
public String check() {
return "checked " + this.test;
}
}
public class TestService {
public String purchaseProduct(String param) {
A a = new A(param);
return a.check();
}
}
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
public class ConstructorMockTest {
private MockedConstruction<A> mockAController;
#BeforeEach
public void beginTest() {
//create mock controller for all constructors of the given class
mockAController = Mockito.mockConstruction(A.class,
(mock, context) -> {
//implement initializer for mock. Set return value for object A mock methods
when(mock.check()).thenReturn(" Constructor Mock A ");
});
}
#Test
public void test() {
//each instantiation of class A will return new mock, which initialized by initializer from beginTest method
//new mock will be stored to mockAController.constructed() collection of mocks
A aObject = new A("test");
//ensure that method check() returns mocked value
Assertions.assertEquals(aObject.check(), " Constructor Mock A ");
//get just created mock for class A from controller. It will be first element of mockAController.constructed() collection
A aMock = mockAController.constructed().get(0);
//ensure that we get correct mock from mock controller, that it is equal from new created object
Assertions.assertEquals(aMock, aObject);
//verify that check method was executed on Mock
verify(aMock, times(1)).check();
//create new A object, new mock created and stored to mockAController.constructed()
A aObject2 = new A("test");
//ensure that method check() returns mocked value
Assertions.assertEquals(aObject2.check(), " Constructor Mock A ");
//get just created mock for class A from controller, it will be second object from constructed collection
A aMock2 = mockAController.constructed().get(1);
//ensure that we get correct mock from mock controller, that it is equal from just created A object
Assertions.assertEquals(aObject2, aMock2);
//verify that check method was executed on Mock
verify(aMock2, times(1)).check();
//Example of testing service which creates A object
TestService service = new TestService();
String serviceResult = service.purchaseProduct("test");
//ensure that service returned value from A mock
Assertions.assertEquals(serviceResult, " Constructor Mock A ");
//get just created mock for class A from controller, it will be third object from constructed collection
A aMock3 = mockAController.constructed().get(2);
//verify that check method was executed on Mock
verify(aMock3, times(1)).check();
}
#AfterEach
public void endTest() {
mockAController.close();
}
}
Let's rewrite your test. I do not have the full code, but I will try to create an example with comments:
#Test
void shouldThrowException() throws Exception {
//given
UrlLinkDto urlLinkDto =
UrlPartLinkDto.builder().callId("333").videoId("5555544").build();
ArgumentCaptor<UrlPartLinkDto> argumentCaptor = ArgumentCaptor.forClass(UrlPartLinkDto.class);
try (MockedConstruction<ObjectMapper> objectMapperMockedConstruction = mockConstruction(ObjectMapper.class,
(objectMapper, context) -> {
//initialize ObjectMapper mock to throw exception when argumentCaptor will come to writeValueAsString method
doThrow(JsonProcessingException.class).when(objectMapper).writeValueAsString(argumentCaptor.capture());
})) {
//execute service for testing and catch exception
Throwable throwable = catchThrowable(() -> partUnlinkService.unlink(urlLinkDto, false));
//verify that inner service was executed
verify(partLogCheckService, times(1)).checkForExistingVideo(urlLinkDto.getVideoId());
//verify that ObjectMapper was instantiated
Assertions.assertEquals(1, objectMapperMockedConstruction.constructed().size());
//get mock of ObjectMapper which was instantiated during service execution
ObjectMapper objectMapper = objectMapperMockedConstruction.constructed().get(0);
//verify that writeValueAsString was executed
verify(objectMapper, times(1)).writeValueAsString(argumentCaptor.capture());
//check that exception is correct
assertThat(throwable).isInstanceOf(JsonProcessingException.class);
}
}
I think I have the same question as you, hope someone can solve our problem.
In my case, I also want to got a return object like PowerMock.whenNew().withArguments().thenReturn(someThing), I try a lot of times but it failed.
I think mockConstruction just only can mock their behavior, can't verify their result like powerMock, and I couldn't find any articles or answers.
below is my post link :
Junit 5 use mockConstruction().withSetting().useConstructor() instead of PowerMock.whenNew().withArguments()

Unable to execute test method from mocked class

I am writing unit test for methods to find banks near my location.
I mocked the class and tried to call the methods.
But, control is not going to method to execute it.
Below is unit test case.
#Test
public void testFindBanksByGeo() {
String spatialLocation = "45.36134,14.84400";
String Address = "Test Address";
String spatialLocation2 = "18.04706,38.78501";
// 'SearchClass' is class where 'target' method resides
SearchClass searchClass = Mockito.mock(SearchClass.class);
BankEntity bank = Mockito.mock(BankEntity.class);
// 'findAddressFromGeoLocation' and 'getGeo_location' to be mocked. They are called within 'target' method
when(searchClass.findAddressFromGeoLocation(anyString())).thenReturn(Address);
when(bank.getGeo_location()).thenReturn(spatialLocation2);
// 'writeResultInJson' is void method. so needed to 'spy' 'SearchClass'
SearchClass spy = Mockito.spy(SearchClass.class);
Mockito.doNothing().when(spy).writeResultInJson(anyObject(), anyString());
//This is test target method called. **Issue is control is not going into this method**
SearchedBanksEntity searchBanksEntity = searchClass.findNearbyBanksByGeoLocation(spatialLocation, 500);
assertNull(searchBankEntity);
}
What i have tried is also calling the real method on it,
Mockito.when(searchClass.findNearbyBanksByGeoLocation(anyString(), anyDouble())).thenCallRealMethod();
This calls real method but the methods i mocked above, are executing like real one. Means 'mocked methods' are not returning what i asked them to return.
So, what wrong i am doing here ?
why method is not executing?
The method is not getting called because you are calling it on a mock. You should call the method on an actual object.
Or you could use something like this before invoking the method.
Mockito.when(searchClass.findNearbyBanksByGeoLocation(Mockito.eq(spatialLocation), Mockito.eq(500))).thenCallRealMethod();
But I think this is not the way you should write the test. You shouldn't be mocking SearchClass in the first place. Instead there would be a dependency in SearchClass which gets you the address and geo location. You should be mocking that particular dependency.
OK, let's say we have this code:
class Foo {
// has a setter
SomeThing someThing;
int bar(int a) {
return someThing.compute(a + 3);
}
}
We want to test Foo#bar(), but there's a dependency to SomeThing, we can then use a mock:
#RunWith(MockitoJunitRunner.class)
class FooTest {
#Mock // Same as "someThing = Mockito.mock(SomeThing.class)"
private SomeThing someThing,
private final Foo foo;
#Before
public void setup() throws Exception {
foo = new Foo(); // our instance of Foo we will be testing
foo.setSomeThing(someThing); // we "inject" our mocked SomeThing
}
#Test
public void testFoo() throws Exception {
when(someThing.compute(anyInt()).thenReturn(2); // we define some behavior
assertEquals(2, foo.bar(5)); // test assertion
verify(someThing).compute(7); // verify behavior.
}
}
Using a mock we are able to avoid using a real SomeThing.
Some reading:
http://www.vogella.com/tutorials/Mockito/article.html
https://github.com/mockito/mockito/wiki

How do I mock call method from testable class?

Want to ask you a question.
How should I properly return some data from method called from testable class ?
For example I have next structure:
Class SomeClass {
public void method1(){
//some logic here
List<Object> howToReturnHereValues = gatData();
//some logic here
}
public List<Object> getData(){
return List<Object>;
}
}
Right now I want to test method1(), but I don't know how to mock call getData() which returns List<Object>.
Any advice please ?
You can do this using a spy, like explained here: https://static.javadoc.io/org.mockito/mockito-core/2.7.17/org/mockito/Mockito.html#13
Example:
#Test
public void testMethod1() throws Exception {
SomeClass someClass = new SomeClass();
SomeClass spy = Mockito.spy(someClass);
Mockito.when(spy.getData()).thenReturn(Arrays.asList("blaat", "blabla"));
spy.method1();
}
This will return a List of "blaat" and "blabla" which can be used by the logic in your method1.
Right now I want to test method1(), but I don't know how to mock call
getData() which returns List.
It is rather a bad idea to mock a public method of a class that is under test.
A unit test should test a behavior and mock dependencies. Here, you unit test only a part of the behavior as you mock the behavior of the tested class.
If the class is ours you could :
either test this method without mocking the getData() called public method.
or move the getData() public method in another class and then mock this new dependency if you don't want to repeat the test of the getData() method in each test method calling it.
If the class is not modifiable and the mocked called is really required, you could use the spy() method of the Mockito framework on the object under test to simulate a mocked behavior for a specific method.

mockito stub makes no difference to test result?

I'm new to Mockito and working on a basic example below. If I comment out the stubbed line below the test still passes, what am I doing wrong?
I would have expected the test to fail if I remove the stubbed line as the 'serviceUnderTest' would then not return the correct result from the underlying call to the 'doSomething' method in the mocked dependency?
public class MyTest {
private MyService serviceUnderTest;
#Mock
private MyHelper mockedDependency;
#Before
public void doBeforeEachTestCase()
{
MockitoAnnotations.initMocks(this);
serviceUnderTest = new MyServiceImpl();
serviceUnderTest.setMyHelper(mockedDependency);
}
#Test
public void test1()
{
try
{
SomeObject someObject = null;
// create my stub
stub(mockedDependency.doSomething("123", false, false)).thenReturn(someObject);
// run the implementation
ServiceResult serviceResult = serviceUnderTest.anotherMethod("123", false, false);
// check the state
assertNotNull(serviceResult);
// check the behaviour of the mock
verify(mockedDependency).doSomething("123", false, false);
}
catch(Exception e)
{
fail();
}
}
}
At the time you do your stubbing, someObject is null. So you're setting up the mock to return null from that method.
But null is the default value that a mock will return anyway, from a method that returns an object. Your stubbing actually makes no difference. Note that there are some exceptions to this rule.
If a method returns a collection, then the default return will be an empty collection.
If a method returns one of the wrapper types, then the default return will be zero or false, rather than null.
The toString method returns the name of the mock.
Turns out it was my own misunderstanding of Mockito!
The test was always passing because of the irrelevance of the stubbed method in this case. The stubbed method is used to provide a response to a method call in the service under test, it does not mean that the actual method that I'm verifying at the end of the test is not called.
The method I'm verifying is called in the service under test and the stub makes no difference to this, hence it passes.
At first, if it's a pure unit test you can get rid of #Before section using #RunWith and #InjectMocks annotations. They will handle the initialization phase.
Second, you don't nee to put try-catch blocks, you can just declare the Exception in your testMethod.
And it's better to use when() instead of stub(), like this:
#RunWith(MockitoJUnitRunner.class) public class MyTest {
#Mock
private MyHelper mockedDependency;
#InjectMocks
private MyService serviceUnderTest;
#Test
public void test1() throws Exception {
SomeObject someObject = null;
// create my stub
when(mockedDependency.doSomething("123", false, false)).thenReturn(someObject);
// run the implementation
ServiceResult serviceResult = serviceUnderTest.anotherMethod("123", false, false);
// check the state
assertNotNull(serviceResult);
// check the behaviour of the mock
verify(mockedDependency).doSomething("123", false, false);
}}
In your case line when(mockedDependency.doSomething is not important - test is checking the desired behaviour of MyServiceImpl anyway.

Nested mocking in Mockito

I have this Mockito code:
interface Dao {
public void doSomething();
}
class LegacyClass {
Dao dao;
public String legacyMethod() {
dao.doSomething();
return "Test";
}
}
public class MockitoTest {
public static void main(String[] args) {
Dao dao = mock(Dao.class);
LegacyClass legacyInst = new LegacyClass();
legacyInst.dao = dao;
LegacyClass legacy = spy(legacyInst);
when(legacy.legacyMethod()).thenReturn("Replacement");
}
}
The last when() throws the following exception:
Exception in thread "main" org.mockito.exceptions.base.MockitoException:
'doSomething' is a *void method* and it *cannot* be stubbed with a *return value*!
Voids are usually stubbed with Throwables:
doThrow(exception).when(mock).someVoidMethod();
If the method you are trying to stub is *overloaded* then make sure you are calling the right overloaded version.
at mypkg.MockitoTest.main(MockitoTest.java:28)
However, I am NOT mocking return value for Dao.doSomething, but for LegacyClass.legacyMethod().
Is this the expected behavior? Are there any Mockito docs stating you cannot nest mocks like this?
How can I walk this around?
Spies don't work this way. In your sample code, the real method legacy.legacyMethod() is actually called because it's a spy not a mock (which then calls dao.doSomething()), that's why you are getting this error.
If you want to make a partial mock, you have to write this as :
doReturn("Replacement").when(legacy).legacyMethod();
That way Mockito will know that you want to make a partial mock, so it won't call the real method.

Categories

Resources