Is it possible give a mock as argument while injecting other mocks? - java

I am using JUnit5.
I have following scenario:
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class SomeClassTest {
// needs to be mocked but not injected
#Mock
private EntityManager entityManager;
// needs to be mocked and injected
#Mock
private SomeDao someDao;
#InjectMocks
private SomeClass someClass = new someClass(entityManager);
public class SomeClass{
EntityManager entityManager;
public SomeClass(EntityManager entityManager) {
if (entityManager == null) {
throw new NullpointerException("Manager is null");
} else {
this.entityManager = entityManager;
}
The problem is:
mocked EntityManager object is needed to create the class I want to test
must inject SomeDao which is needed in SomeClass
I get a nullpointer because the mocked object appears not to be created when I give it as argument to the constructor
Has anybody an idea how to solve this? I could create a no-arg constructor but that would give me a constructor which I only need for testing which isn't that 'clean'.

You should add your SomeDao someDao as an arg to SomeClass constructor and then you will be able to manipulate it via tests using #Mock

Looking at this answer (https://stackoverflow.com/a/67081911/11431537) Mockito is using 3 ways to inject a mock.
The first one is injecting it in the constructor if there is a constructor which takes the argument.
Therefore, I changed my constructor as #nesmeyana mentioned:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import javax.persistence.EntityManager;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
#ExtendWith(MockitoExtension.class)
public class SomeClassTest {
#Mock
private EntityManager mockEntityManager;
#Mock
private SomeDao mockSomeDao;
#InjectMocks
private SomeClass someClass;
#Test
public void test() {
when(mockSomeDao.duck()).thenReturn(10);
assertEquals(10, someClass.bla());
}
}
public class SomeClass{
EntityManager entityManager;
SomeDao someDao;
public SomeClass(EntityManager entityManager, SomeDao someDao) {
if (entityManager == null) {
throw new NullpointerException("Manager is null");
} else {
this.entityManager = entityManager;
this.someDao = someDao;
}
public class SomeDao{
int x = 5;
public SomeDao(int x) {
this.x = x;
}
public int duck() {
return x;
}
}
But since I had to change my code to be able to test my classes, I have to rethink my code writing in general!
I and everybody who reads this, should avoid hard dependencies and use CI (dependency injection) to be able to test their code easily.

Related

Mock a method coming from parent class to return a mocked data

I have a method coming from another class which is the super class
for the method I am testing. I wish to mock it such that when I reach that method,
I just want to return a mocked data.
But currently, it keeps going into the method instead of skipping it and just assigning the mock data.
Could I please get some help on why my mocking is not working?
Please note that the parent class is actually coming from another dependency which we do not maintain and it's accessibility is protected.
Thus can't refactor the method being mocked and not looking to refactor the code. Just want to mock it.
Looking to achieve this either via mockito or powermock or combined if it comes to that. Thanks. ## Heading ##
This is the class and method being tested.
#Service
public class OfferService extends ParentClass {
// many other methods
public Object get() {
// getHttpEntity() comes from ParentClass
HttpEntity<Object> httpEntity = getHttpEntity("www.example.com"); // looking to mock this getHttpEntity method. I do not want to enter it.
// will not reach here. Failed at above line cos didn't mock getHttpEntity.
ResponseEntity<OfferResponses> responseEntity = restTemplate.exchange(endPoint, HttpMethod.GET, httpEntity, OfferResponses.class);
return responseEntity.getBody();
}
}
My Test which currently fails cos it keeps entering the getHttpEntity method.
package com.pack;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.whenNew;
#RunWith(PowerMockRunner.class)
public class OfferServiceTest {
#InjectMocks
OfferService offerService;
#Mock
RestTemplate restTemplate;
#Mock
HttpEntity<Object> entity;
#Before
public void setup() {
offerService = new OfferService();
MockitoAnnotations.initMocks(this);
}
// failing test
#Test
public void getTest() throws Exception {
OfferResponses offerResponses = new OfferResponses();
ResponseEntity<OfferResponses> responseEntity = new ResponseEntity<>(offerResponses, HttpStatus.OK);
PowerMockito.when(
restTemplate.exchange(anyString(), Matchers.eq(HttpMethod.GET)
, Matchers.anyObject(),
Matchers.<Class<OfferResponses>>anyObject()))
.thenReturn(responseEntity);
OfferService spy = spy(offerService);
doReturn(entity).when(spy, "getHttpEntity", Matchers.anyString());
Object result = offerService.get();
// assertions
}
}
So, since you want to spy your OfferService, you must invoke your get method on this spy.
With PowerMockito:
#RunWith(PowerMockRunner.class)
public class OfferServiceTest {
#Spy
#InjectMocks
private OfferService offerService = new OfferService();
#Mock
private RestTemplate restTemplate;
#Mock
private HttpEntity<Object> entity;
#Test
public void test() {
PowerMockito.when(offerService, "getHttpEntity", "www.example.com")
.thenReturn(entity);
PowerMockito.when(restTemplate.exchange(anyString(), any(), any(), any()))
.thenReturn(something);
assertEquals(someObject, offerService.get());
}
}
Or it can be done without PowerMockito using ReflectionTestUtils:
#ExtendWith(MockitoExtension.class)
public class OfferServiceTest {
#Spy
#InjectMocks
private OfferService offerService;
#Mock
private RestTemplate restTemplate;
#Mock
private HttpEntity<Object> entity;
#Test
public void test() {
when(ReflectionTestUtils.invokeMethod(offerService, "getHttpEntity", "www.example.com"))
.thenReturn(entity);
when(restTemplate.exchange(anyString(), any(), any(), any()))
.thenReturn(something);
assertEquals(someObject, offerService.get());
}
}

Mock method in abstract class that inherit abstract class

I have a service that extends abstract class in my spring-boot project
public class TestService extends AbstractTest1Service {
// some methods
}
public abstract class AbstractTest1Service extends AbstractTest2Service {
public String doSomething() {
return writeText();
}
}
public abstract class AbstractTest2Service {
String writeText() {
return "text";
}
}
Is there any way to mock writeText() method when i want to test TestService:
Your TestService class:
public class TestService extends AbstractTest1Service {
AbstractTest2Service abstractTest2Service;
public String doSomething() {
abstractTest2Service.writeText();
System.out.println("Passed!");
return "All Checked";
}
}
Your TestServiceTest class should be like:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class TestServiceTest {
#InjectMocks
TestService testService;
#Mock
AbstractTest2Service abstractTest2Service;
#Test
public void testService(){
Assert.assertEquals("All Checked",testService.doSomething());
}
}
Note: Do not use #Spy instead of #Mock , Spy will try to check the actual implementation of the abstract class methods which is not
there , so your test will be ignored. Just use #Mock.
Using #Spy will give error:
Cannot instantiate a #Spy for 'abstractTest2Service' field. You
haven't provided the instance for spying at field declaration so I
tried to construct the instance. However, I failed because: the type
'AbstractTest2Service is an abstract class.

Mockito with Jersey Test and JAX-RS - UnsatisfiedDependencyException

Trying to test a fairly simple JAX-RS endpoint
#ApplicationScoped
#Path("mypath")
public class MyRestService {
#Inject
private Logger logger;
#Inject
private EjbService ejbService;
#GET
public String myMethod() {
logger.info("...");
return ejbService.myMethod();
}
}
with Mockito and Jersey Test
#RunWith(MockitoJUnitRunner.class)
public class MyRestServiceTest extends JerseyTest {
#Mock
private EjbService ejbService;
#Mock
private Logger logger;
#InjectMocks
private MyRestService myRestService;
...
#Override
protected Application configure() {
MockitoAnnotations.initMocks(this);
return new ResourceConfig().register(myRestService);
}
}
The Grizzly container is returning a org.glassfish.hk2.api.UnsatisfiedDependencyException for Logger and EjbService even thought the dependencies are injected correctly by Mockito.
Seems Grizzly is trying, correctly, to ovverride the Mockito mocks.
If I register an AbstractBinder in the configure method, everything works fine.
.register(new AbstractBinder() {
#Override
protected void configure() {
bind(ejbService).to(EjbService.class);
bind(logger).to(Logger.class);
}
});
But I don't feel it's the best way to accomplish injection. Mockito style is better imho.
What do I need to do to solve this issue?
I was able to create the following base class in order to achieve integration between JerseyTest and Mockito such as the OP aimed for:
package org.itest;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.test.JerseyTestNg;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.util.ReflectionUtils;
import javax.ws.rs.core.Application;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* #author Nom1fan
*/
public abstract class JerseyTestBase extends JerseyTestNg.ContainerPerClassTest {
#Override
protected Application configure() {
MockitoAnnotations.openMocks(this);
ResourceConfig application = new ResourceConfig();
Object resourceUnderTest = getResourceUnderTest();
application.register(resourceUnderTest);
Map<String, Object> properties = Maps.newHashMap();
properties.put(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
properties.put("contextConfigLocation", "classpath:applicationContext.xml");
// Retrieve the fields annotated on subclass as #Mock via reflection and keep each instance
// and its type on an entry in the map, later used to bind to Jersey infra.
HashMap<Object, Class<?>> mocksToBindMap = Maps.newHashMap();
List<Field> fieldsWithMockAnnotation = FieldUtils.getFieldsListWithAnnotation(getClass(), Mock.class);
for (Field declaredField : fieldsWithMockAnnotation) {
declaredField.setAccessible(true);
Object fieldObj = ReflectionUtils.getField(declaredField, this);
mocksToBindMap.put(fieldObj, declaredField.getType());
}
application.setProperties(properties);
application.register(new AbstractBinder() {
#Override
protected void configure() {
for (Map.Entry<Object, Class<?>> mockToBind : mocksToBindMap.entrySet()) {
bind(mockToBind.getKey()).to(mockToBind.getValue());
}
}
});
return application;
}
protected abstract Object getResourceUnderTest();
}
The hook getResourceUnderTest must be implemented by the extending test class, providing the instance of the resource it wishes to test.
Test class example:
import org.itest.JerseyTestBase;
import org.mockito.InjectMocks;
import org.mockito.Mock;
public class MyJerseyTest extends JerseyTestBase {
#Mock
private MockA mockA;
#Mock
private MockB mockB;
#InjectMocks
private MyResource myResource;
#Override
protected Object getResourceUnderTest() {
return myResource;
}
#Test
public void myTest() {
when(mockA.foo()).thenReturn("Don't you dare go hollow");
when(mockB.bar()).thenReturn("Praise the Sun \\[T]/");
// Test stuff
target("url...").request()...
}
}
MyResource class looks something like this:
#Path("url...")
#Controller
public class MyResource {
private final MockA mockA;
private final MockB mockB;
#Autowired // Mocks should get injected here
public MyResource(MockA mockA, MockB mockB) {
this.mockA = mockA;
this.mockB = mockB;
}
#GET
public Response someAPI() {
mockA.foo();
mockB.bar();
}
}
NOTE: I used Spring's and Apache's reflection utils to make things easier but it's not mandatory. Simple reflection code which can be written by hand.
The MockitoJUnitRunner is for unit tests and JerseyTest is for integration tests.
When using Mockito, your tests will call directly the declared myRestService and Mockito dependency injection will take place.
When using JerseyTest, a new web container is created and your tests talk to MyRestService via an HTTP call. Inside this container, the real dependency injection is happening, the classes are not even seeing you declared mocks.
You can use JerseyTest and Mockito together, exactly as you did. It just requires some extra configurations (as you already found) and the #RunWith annotation is not necessary.

Mockito Test Failed: Actually, there were zero interactions with this mock

Just wanna ask as I am stuck in the test cases and getting error as "Actually, there were zero interactions with this mock".
I have created an Dao Implementation class which is doing CRUD operation.
public class EmployeeDaoImpl implements EmployeeDao {
#Override
public void saveEmployee(EmployeeDetails employee) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.save(employee);
transaction.commit();
session.close();
}
}
And for this above class I am building the test using Mockito. So for my above saveEmployee method Session, TRansaction I have made it as Mock object and now I need to check session , save method and transaction as well.
So I have written the Mockito code below:
/**
*
*/
package sandeep.test;
import static org.junit.Assert.*;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import junit.framework.Assert;
import org.hibernate.Session;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import sandeep.DAO.EmployeeDao;
import sandeep.DAOImpl.EmployeeDaoImpl;
import sandeep.DAOImpl.HibernateUtil;
import sandeep.pojo.EmployeeDetails;
import static org.mockito.Mockito.*;
/**
* #author sandeep
*
*/
#RunWith(MockitoJUnitRunner.class)
public class EmployeeDaoImplTest {
#Mock
EmployeeDetails edt;
#Mock
Session session ;
#Mock
Transaction transaction;
#InjectMocks
EmployeeDaoImpl edi = new EmployeeDaoImpl();
#Before
public void setUp() throws Exception {
//eimpl = new EmployeeDaoImpl();
//emp= mock(EmployeeDao.class);
}
#After
public void tearDown() throws Exception {
}
#Test
public void testSaveEmployee(){
edi.saveEmployee(getEmployeeDetails());
// But here i am getting the error as zero interactions
verify(session, times(1)).save(EmployeeDetails.class);
}
public EmployeeDetails getEmployeeDetails(){
edt = new EmployeeDetails();
edt.setEname("sandeep");
edt.setId(2);
edt.setEnumber("hoi");
return edt;
}
}
I have debugged the code and the code is passing onto all the breakpoints in my IDE and when I execute this the 3 values it will be added to the database but my test case will fail as there are zero interactions.
The Session mock in your test is not the same object used in EmployeeDaoImpl#saveEmployee
Implement a constructor for EmployeeDaoImpl with a Session argument and use that argument in the saveEmployee() method. This allows your #InjectMocks to work as intended.
#RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
#Mock
Session session;
#InjectMocks
EmployeeDaoImpl edi;
#Test
public void testSaveEmployee(){
edi.saveEmployee();
verify(session, times(1)).save();
}
}
class Session {
void save() {
System.out.println("saving");
}
}
interface EmployeeDao {
void saveEmployee();
}
class EmployeeDaoImpl implements EmployeeDao {
private Session session;
public EmployeeDaoImpl(Session session) {
this.session = session;
}
#Override
public void saveEmployee() {
session.save();
}
}

Mockito.doNothing() keeps returning null pointer exception

I know I should not be testing void methods like this, but I am just testing Mockito.doNothing() as of now with a simple example.
My Service class:
#Service
public class Service{
#Autowired
private Consumer<String, String> kafkaConsumer;
public void clearSubscribtions(){
kafkaConsumer.unsubscribe();
}
}
My Test class:
#MockBean
private Consumer<String, String> kafkaConsumer;
#Test
public void testClearSubscriptions() {
Service service = new Service();
Mockito.doNothing().when(kafkaConsumer).unsubscribe();
service.clearSubscriptions();
}
The test keeps failing with a null pointer exception. When I debugged it, it goes into the clearSubscription method of the service class, and there on the line of kafkaConsumer.unsubscribe(), kafkaConsumer is null. But I mocked the consumer, why is it throwing null pointer exception and I should be skipping over that method, right?
Edit:
All the declarations of the class:
#Autowired
private Consumer<String, String> kafkaConsumer;
#Autowired
private Service2 service2;
private final Object lock = new Object();
private static Logger logger = LoggerFactory.getLogger(Service.class);
private HashMap<String, String> subscribedTopics = new HashMap<>();
Figured out what was wrong, I needed to auto wire the service
You are instantiating a new service Service service = new Service(); but from what I can see you are never injecting the mock bean into the new service.
Here is a sample of what I think you could do if you are using mockito only and dont need to instantiate a spring container (used a single class for ease of example dont do this in actual code):
package com.sbp;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#RunWith(MockitoJUnitRunner.class) // run with mockitos runner so annotations are processed
public class MyServiceTest {
public interface Consumer<T, R> {
public void unsubscribe();
}
#Service
public class KafkaConsumer implements Consumer<String, String> {
#Override
public void unsubscribe() {
}
}
#Service
public class MyService {
#Autowired
private Consumer<String, String> kafkaConsumer;
public void clearSubscriptions() {
kafkaConsumer.unsubscribe();
}
}
#Mock // tell mockito that this is a mock class - it will instantiate for you
private Consumer<String, String> kafkaConsumer;
#InjectMocks // tell mockito to inject the above mock into the class under test
private MyService service = new MyService();
#Test
public void testClearSubscriptions() {
service.clearSubscriptions();
Mockito.verify(kafkaConsumer, Mockito.times(1)).unsubscribe();
}
}
If you need an example via Spring using MockBean or without and dependencies, let me know and I can post.
UPDATED: adding sample using spring junit runner and using spring boot's mockbean annotation
package com.sbp;
import com.sbp.MyServiceTest.TestContext.MyService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class) // run with spring
#SpringBootTest(classes = MyServiceTest.TestContext.class) // make it a spring boot test so #MockBean annotation is processed, provide a dummy test context class
public class MyServiceTest {
public interface Consumer<T, R> {
public void unsubscribe();
}
#Configuration
public static class TestContext {
#Service
public class KafkaConsumer implements Consumer<String, String> {
#Override
public void unsubscribe() {
}
}
#Service
public class MyService {
#Autowired
private Consumer<String, String> kafkaConsumer;
public void clearSubscriptions() {
kafkaConsumer.unsubscribe();
}
}
}
#MockBean // this will create a mockito bean and put it in the application context in place of the Kafka consumer bean defined in the TestContext class
private Consumer<String, String> kafkaConsumer;
#Autowired // inject the bean from the application context that is wired with the mock bean
private MyService myService;
#Test
public void testClearSubscriptions() {
myService.clearSubscriptions();
Mockito.verify(kafkaConsumer, Mockito.times(1)).unsubscribe();
}
}

Categories