How to mock or prepare test methods in case we called private method inside the method? - mockito

While writing a testCase for Controller class,The private method that is getServiceContext(). has different object because
one we are passing serviceContext from testclass and other object inside the controller class itself call itself.Due to this Foo object is null. how to resolve this.
public class Controller {
#Refernce
private FooService fooService;
public CustomData getDetails(String id){
Foo foo = fooService.getFoo(id ,**getServiceContext()**);
//getServiceContext() is different object
System.out.println("foo data>>>> "+foo); // **Throwing null pointer exceptions**
CustomData customData = new CustomData();
customData.setStudentName(foo.getName);
customData.setStudentName(foo.getId);
...
...
...
return customData;
}
private ServiceContext getServiceContext() {
ServiceContext serviceContext = new ServiceContext();
serviceContext.setCompanyId(context..);
serviceContext.setUserId(context..);
...
....
retrn serviceContext;
}
}
public class ControllerTest {
#InjectMocks
private Controller controller;
#Mock
private FooService fooService;
private Foo foo;
#BeforeEach
public void setUp() throws PortalException {
foo = mock(Foo.class);
}
#Test
public void getDetailsTest() throws Exception {
ServiceContext **serviceContext** = new ServiceContext();
serviceContext.setCompanyId(context..);
serviceContext.setUserId(context..);
...
....
Mockito.when(fooService.getFoo("testId",serviceContext)).thenReturn(foo);
System.out.println("Service context>>>> "+**serviceContext**); // different serviceContext object
CustomData customData = controller.getDetails("testId");
Assertions.assertThat(ss).isNotNull();
}
}

There are multiple ways to do that.
First, we can mock with anyOf(Type.class), that will actually match object type rather than value.
Mockito
.when(fooService.getFoo(Mockit.eq("testId"), Mockito.any(ServiceContext.class)))
.thenReturn(foo);
this will work as expected and return the desired value.
Additionally, if you want to check with what data serviceContext object is being passed as arg in service method, (as we just checked object type rather than value), We can use ArgumentCaptor for that.
It basically captures argument data which is being passed in the method call.
let's create ArgumentCaptor for service context
#Mock
private FooService fooService;
#Captor
private ArgumentCaptor<ServiceContext> captor;
Now, let's capture the argument during verification.
Mockito.verify(fooService).getFoo(Mockit.eq("testId"), captor.capture());
Assertions.assertEquals("value of x in context", captor.getValue().getX());
Basically here, captor.getValue() returns service context object which is being passed. So, you can verify all data you want to validate in that object.
Alternate, Approach would be Spy which will basically spy on the class under test and you can control the behavior of private methods in test class itself.
To do that, we need to add #Spy annotation along with #InjectMocks on test class.
#Spy
#InjectMocks
private Controller controller;
Now, you can mock the private method and return the expected value.
Mockito.doReturn(serviceContextValue).when(controller).getServiceContext();
and use that object for mocking fooService.
Mockito.verify(fooService).getFoo("testId", serviceContextValue);
But when using Spy, don't forget to write unit test for private method as it's mocked, it's business logic will not be tested by above test cases. that's a reason, it's not recommended way.
I would suggest using ArgumentCaptor approach.

Related

Wanted to but not invoked. Mockito

I have a question. Maybe it is very basic. Can we do this
without actually invoking the method in our test class?
My Test class:
class Test{
Action action=new Action();
#Mock
Provider provider;
when(provider.getNames()).thenReturn(Arrays.asList("names"));
verify(provider,atLeastOnce()).getNames();
action.update();
}
As you can see, "provider" is only mocked and not explicitly called. The only way it will be called is when I invoke action.update(); I am getting the error
Wanted but not invoked: Actually, there were zero interactions with this mock.
provider.getNames()
class Action{
public void update(){
Provider provider = new Provider();
List<String> l=provider.getNames();
}
}
Your order of operations is wrong. If provider is called when action.update() is called, then you should be verifying after calling action.update():
when(provider.getNames()).thenReturn(Arrays.asList("names"));
action.update(); // Do action first
verify(provider,atLeastOnce()).getNames(); // Then verify outcome of "action"
UPDATE
Your code is not currently testable:
public void update(){
Provider provider = new Provider();
List<String> l=provider.getNames();
}
Your code says "when update is called, make a NEW provider and call getNames on that". Your test says "assert that this random provider that does interact with action at all is called", which will of course never pass.
You need to use dependency injection to pass in the provider you want to use to verify the interaction.
Either pass the provider to the function:
public void update(Provider provider){
List<String> l=provider.getNames();
}
So you can test like this:
action.update(provider)
verify(provider).getNames()
OR pass the provider via constructor:
class Action {
private final Provider mProvider;
// Default constructor can be used in main app as usual
public Action() {
this(new Provider())
}
// Argument constructor can receive a provider that can be mocked
public Action(Provider provider) {
mProvider = provider;
}
public void update(){
// Provider provider = new Provider(); // Don't do this
List<String> l = mProvider.getNames(); // Use constructor provided object
}
Then you can test this:
#Test
public void test() {
Action action = new Action(provider); // Inject mock
action.update();
verify(provider).getNames(); // Now our mock will get called
}

How do I mock both a final and a static using Mockito

So I have a couple Tests that run using mockito. One requires a static to be mocked so I use PowerMockito like this...
BDDMockito.given(WebClient.create(any())).willReturn(webClientMock);
Next I have another test that mocks a final class like this...
HttpSecurity security = Mockito.mock(HttpSecurity.class);
The second one doesn't work at first, I get the following failure....
Cannot mock/spy class org.springframework.security.config.annotation.web.builders.HttpSecurity
Mockito cannot mock/spy because :
- final class
So I looked and found this question which suggests adding the file .../src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker with mock-maker-inline
But when I add that the first line fails with...
org.mockito.exceptions.misusing.NotAMockException: Argument should be a mock, but is: class java.lang.Class
How do I get both to work?
Update
I didn't want to clutter up the question with the entire test which really doesn't provide any extra context. However, since people are insisting and seem to misunderstand the question...
// Static
#ExtendWith(MockitoExtension.class)
#RunWith(PowerMockRunner.class)
#PrepareForTest(WebClient.class)
public class RasaServiceTest {
#Mock
private WebClient webClientMock;
#Mock
private WebClient.RequestHeadersSpec requestHeadersMock;
#Mock
private WebClient.RequestHeadersUriSpec requestHeadersUriMock;
#Mock
private WebClient.RequestBodyUriSpec requestBodyUriMock;
#Mock
private WebClient.ResponseSpec responseMock;
private MyService service = new MyService();
#BeforeAll
public void setup(){
PowerMockito.mockStatic(WebClient.class);
BDDMockito.given(WebClient.create(any())).willReturn(webClientMock);
}
#Test
public void HappyPath(){
MessageResponseItem item = new MessageResponseItem();
item.setRecipientId("id");
item.setResponseText("response");
MessageResponseItem[] items = {item};
when(webClientMock.post()).thenReturn(requestBodyUriMock);
when(requestHeadersUriMock.uri("/webhooks/rest/webhook")).thenReturn(requestHeadersMock);
when(requestHeadersMock.retrieve()).thenReturn(responseMock);
when(responseMock.bodyToMono(MessageResponseItem[].class)).thenReturn(Mono.just(items));
InferenceEngineRequest request = new InferenceEngineRequest();
MessageResponseItem[] result = service.call(request).block();
assertThat(result.length).isEqualTo(1);
assertThat(result[0].getResponseText()).isEqualTo("response");
}
}
// Final
#RunWith(MockitoJUnitRunner.class)
public class RemoveMeConfigTest {
#Test
public void happyPath() throws Exception {
HttpSecurity security = Mockito.mock(HttpSecurity.class);
CsrfConfigurer<HttpSecurity> csrf = Mockito.mock(CsrfConfigurer.class);
RemoveMeConfig config = new RemoveMeConfig();
Mockito.when(
security.csrf()
).thenReturn(csrf);
Mockito.when(
csrf.disable()
).thenReturn(security);
config.configure(security);
Mockito.verify(
security,
Mockito.times(
1
)
).csrf();
Mockito.verify(
csrf,
Mockito.times(1)
).disable();
}
}

Mockito: How to test a class's void method?

Unit test noob here.
I have three classes: Db1Dao, Db2Dao, ExecuteClass where Db1Dao, Db2Dao are database access objects for two different databases. My goal is to fetch some data from db1 using Db1Dao and run executeClass.execute() to "put" the processed data into db2 using Db2Dao.
My ExecuteClass looks like this:
class ExecuteClass {
private Db1Dao db1Dao;
private Db2Dao db2Dao;
public void execute() {
...
List<String> listOfString = getExternalData(someParam);
List<Metadata> metadatum = db1Dao.get(someInputs);
... I do something to generate a list of new class `A` based on listOfString & metadatum ...
try {
db2Dao.put(listOfA);
} catch (PutException e){
...
}
}
public List<String> getExternalData(SomeClass someParam){
... do something
return listOfString;
}
}
Now I want to test:
Given a specific listOfString (returned by getExternalData) and a specific metadatum (returned by db1Dao.get):
Will I get the desired listOfA?
Am I able to call db2Dao.put and its input parameter is listOfA?
Particularly, I have hard-coded sample listOfString and metadatum and desired listOfA (and they will be passed via an object MockData, see the following code) but I don't know how to write the test using Mockito. The following is a test class I wrote but it does not work:
class TestClass extends BaseTest {
#Mock
private Db1Dao db1Dao;
#Mock
private Db2Dao db2Dao;
private ExecuteClass executeClass;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
executeClass = new ExecuteClass(db1Dao, db2Dao);
}
#ParameterizedTest
#MethodSource("MockDataProvider")
public void executeClassTest(final MockData mockData) throws PutException {
Mockito.when(db1Dao.get(Mockito.any(), ...))
.thenReturn(mockData.getMetadatum());
ExecuteClass executeClassSpy = Mockito.spy(executeClass);
Mockito.when(executeClassSpy.getExternalData(Mockito.any()))
.thenReturn(mockData.getListOfString());
executeClassSpy.execute();
// executeClass.execute(); not working neither...
List<A> listOfA = mockData.getDesiredListOfA();
Mockito.verify(db2Dao).put(listOfA);
}
}
Could anyone please let me know? Thank you in advance!!
You should not create a spy of the same class you want to test. Instead, try to write a unit test for the smallest amount of code (e.g. a public method) and mock every external operator (in your case Db1Dao and Db2Dao).
If testing a public method involves calling another public method of the same class, make sure to mock everything inside the other public method (in your case getExternalData). Otherwise, this other public method might be a good candidate for an extra class to have clear separation of concerns.
So, remove the ExecuteClass executeClassSpy = Mockito.spy(executeClass); and make sure you setup everything with Mockito what's called within getExternalData.
To now actually, verify that Db2Dao was called with the correct parameter, either use your current approach with verifying the payload. But here it's important to 100% create the same data structure you get while executing your application code.
Another solution would be to use Mockito's #Captor. This allows you to capture the value of why verifying the invocation of a mock. Later on, you can also write assertions on the captured value:
#Captor
private ArgumentCaptor<ClassOfListOfA> argumentCaptor;
#Test
public void yourTest() {
Mockito.verify(db2Dao).put(argumentCaptor.capture());
assertEquals("StringValue", argumentCaptur.getValue().getWhateverGetterYouHave);
}
The following code worked for me.
I partially accepted #rieckpil's answer. I used #Captor which is very handy.
The reason I had to mock getExternalData() is because its implementation is still a "TODO".
class TestClass extends BaseTest {
#Mock
private Db1Dao db1Dao;
#Mock
private Db2Dao db2Dao;
#Captor
private ArgumentCaptor<List<A>> argumentCaptor;
private ExecuteClass executeClass;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
executeClass = new ExecuteClass(db1Dao, db2Dao);
}
#ParameterizedTest
#MethodSource("MockDataProvider")
public void executeClassTest(final MockData mockData) throws PutException {
Mockito.when(db1Dao.get(Mockito.any(), ...))
.thenReturn(mockData.getMetadatum());
ExecuteClass executeClassSpy = Mockito.spy(executeClass);
Mockito.when(executeClassSpy.getExternalData(Mockito.any()))
.thenReturn(mockData.getListOfString());
executeClassSpy.execute();
List<A> listOfA = mockData.getDesiredListOfA();
Mockito.verify(db2Dao).put(argumentCaptor.capture());
assertEquals(listOfA, argumentCaptor.getValue());
}
}

Mockito Method calls

I have a DAO implementation class :
public class DataPollingDAOImpl implements DataPollingDAO {
public List<String> getInfo(String id,String columnName)
{
// some code which calls the database and retrieves data.
}
}
I have written a mockito test case as follows-
public class connection{
#Mock private DataPollingDAOImpl myDao;
#Test public void test() {
when(myDao.getInfo("520", "Hole"));
}
}
I created a mock database connection as well. However what shall I do to print success on the console to show a success case after calling myDao.getInfo() in test method?
If you are mocking using #Mock then I suppose you want your mock to return a value, you specify how to return the value by:
when(myDao.getInfo(anyString(), anyString()).thenReturn(Arrays.asList("yourReturnValue"));
If you want to see if you have called your Mock, then normally #Spy is used and you write:
Mockito.verify(myDao).getInfo(anyString(),anyString());
And I do recommend you to use interfaces (as DataPollingDAO) and not implementations (DataPollingDAOImpl)

Mocking two objects of the same type with Mockito

I'm writing unit tests using Mockito and I'm having problems mocking the injected classes. The problem is that two of the injected classes are the same type, and only differentiated by their #Qualifier annotation. If I tried to simply mock SomeClass.class, that mock is not injected and that object is null in my tests. How can I mock these objects?
public class ProfileDAL {
#Inject
#Qualifier("qualifierA")
private SomeClass someClassA ;
#Inject
#Qualifier("qualifierB")
private SomeClass someClassB ;
//...various code, not important
}
#RunWith(MockitoJUnitRunner.class)
public class ProfileDALLOMImplTest {
#InjectMocks
private ProfileDALLOMImpl profileDALLOMImpl = new ProfileDALLOMImpl();
#Mock
private SomeClass someClassA;
#Mock
private SomeClass someClassB;
private SomeResult mockSomeResult = mock(SomeResult.class);
#Test
public void testSomeMethod() {
when(someClassA .getSomething(any(SomeArgment.class)).thenReturn(mockSomeResult);
Int result = profileDALLOMImpl.someTest(This isn't relevant);
}
}
I have tried mocking two objects with the same type with Mockito 1.9.5 using JUnit and it works.
See: http://static.javadoc.io/org.mockito/mockito-core/1.9.5/org/mockito/InjectMocks.html
Relevant type info from the doc:
"Field injection; mocks will first be resolved by type, then, if there is several property of the same type, by the match of the field name and the mock name."
And this one which seems to say you should make the mock name match the field name for all your mocks when you have two of the same type:
"Note 1: If you have fields with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching fields, otherwise Mockito might get confused and injection won't happen."
Perhaps this latter one is biting you?
Just confirmed what Splonk pointed out and it works that way in Mockito 1.9.5, as soon as I removed one of the mocked classes, it failed.
So, in your case, make sure you have both of the mocked classes with the same name as in the class in your test:
#Mock
private SomeClass someClassA;
#Mock
private SomeClass someClassB;
If you don't use annotation, you get something like
public class MyClass {
private MyDependency myDependency;
public void setMyDependency(MyDependency myDependency){
this.myDependency = myDependency;
}
}
and
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;
public class MyTest {
private MyClass myClass;
private MyDependency myDependency;
#Before
public void setUp(){
myClass = new MyClass();
myDependency = mock(MyDependency.class);
myClass.setMyDependency(myDependency);
}
#Test
public void test(){
// Given
// When
// Then
}
}
You can do just the same if your object has its dependencies specified via constructor rather than via setter. I guess your dependency injection framework can annotate the setters the same way you annotate private fields, but now your tests don't rely on any dependency injection framework.

Resources