How to mock only one dependency of test class in spring - java

I have a class, which has a lot of dependencies.
#Service
public class TestClass {
#Inject
private DependencyA dependencyA;
#Inject
private DependencyB dependencyB;
#Inject
private DependencyC dependencyC;
// .
// .
// .
// .
#Inject
private DependencyZ dependencyZ;
public boolean testMethod() {
try {
dependencyA.methodA();
dependencyB.methodB();
dependencyC.methodC();
dependencyD.methodD();
return true;
} catch (StaleObjectStateException e) {
return false;
}
}
}
Now I want to mock one of the dependencies and throw exception to test the catch block of this class.
So following is my test, where I mock dependencyB and throw StaleObjectStateException when dependencyB.methodB(); called.
public class TestClassIT {
#InjectMocks
private TestClass testClass;
#InjectMocks
private CustomRuleEngine customRuleEngine;
#Mock
private DependencyB dependencyB;
#Before
public void init() {
MockitoAnnotations.initMocks(TestClass.class);
}
#Test
public void testOnSuccessRuleAfterCreate() throws Exception {
setupRequestContextWithFullPermission();
when(dependencyB.methodB(any())).thenThrow(new StaleObjectStateException("f", "f"));
// and expect exception.
}
}
However, it doesn't work because all other dependencies of TestClass are injected as a null. How to solve this?
As I mentioned this class has a lot of dependencies and I can't mock each. The requirement is just of mock dependencyB.methodB();

This is one of the cases where property injection is hurting.
Change TestClass to use constructor injection. Then you can instantiate it in your test yourself and inject whatever you want.

You have to define all your dependencies as mocks, not just DependencyB, so Mockito can do the injection. Even if you do not mock their methods, this way, there won't be null fields in your TestClass.
#Mock
private DependencyA dependencyA;
#Mock
private DependencyB dependencyB;
#Mock
private DependencyC dependencyC;

Related

#InjectMocks is not injecting the the list dependency, which is a #Spy

Servcice.java (class to test)
class Service {
#Autowired
private List<Metric> dependency1;
#Autowired
private Executor dependency2;
}
Metric.java : interface
interface Metric{
public void fetchMetric();
}
class Metric1 implements Metric{
public void fetchMetric() {}
}
class Metric2 implements Metric{
public void fetchMetric() {}
}
ServiceTest.java : (test class)
#ExtendWith(MockitoExtension.class)
class ServiceTest {
#Spy
private List<Metric> dependency1;
#Mock
private Executor dependency2;
#InjectMocks // class under test // this has above two as their dependencies.
Service service;
#Mock
private Metric1 metric1;
#Mock
private Metric2 metric2;
#BeforeEach
void setUp() {
// intializing the spy object list with mocks.
this.dependency1 = Arrays.asList(metric1,
metric2
);
}
#Test
void someTest() {
// here in debug mode I can see that `dependency1` as a **spy** and 'dependency1' present in the 'Service' are different, though they should be same.
}
}
Why #InjectMock is not able to Inject a #Spy List dependencies in the Service class object? Am I missing something here.
dependency1 as a spy and dependency1 present as a part of the Service are shown as two different objects on the de-bugger and making the test cases fail. I thought they should be the same.
Should we not initialise the Spies in #BeforeEach method ?
The problem is you use #ExtendWith(MockitoExtension.class) to tell mockito to instantiate your #Mocks #Spy and #InjectMocks. So after Mockito does this you change the field ServiceTest.dependency1 to be a list.
But since Mockito instantiated your CUT with the annotated dependencies, it is not updated when you change the ServiceTest.dependency1.
I would recommend to change Service to have a constructor so you can use the recommended constructor Injection.
That way you can make your test like this:
#ExtendWith(MockitoExtension.class)
class ServiceTest {
#Mock
private Executor dependency2;
Service service;
#Mock
private Metric1 metric1;
#Mock
private Metric2 metric2;
#BeforeEach
void setUp() {
// intializing the spy object list with mocks.
service = new Service(Arrays.asList(metric1,metric2), dependency2);
}
}
If you want the list to be a spy, I would do something like this:
#ExtendWith(MockitoExtension.class)
class ServiceTest {
#InjectMocks
private Service service;
#Mock
private Executor dependency2;
#Spy
private List<Metric> dependency1;
#Test
void test() {
// you can define what to return when there is a method call on the spy dependency1
Metric metric1 = mock(Metric.class);
Metric metric2 = mock(Metric.class);
when(dependency1.get(0)).thenReturn(metric1);
when(dependency1.get(1)).thenReturn(metric2);
service.test();
}
}
One way to handle it:
Remove #Spy and use #Mock on dependency1.
And you will need to handle the List w.r.t. the testcase like:
Mockito.doReturn(metric1).when(dependency1).get(ArgumentMatchers.anyString());

Junit ignore method mocking

I have created a Junit test case in an existing class where I want to ignore few mocks
#InjectMock
private HomeService homeService;
#Mock
private HomeUtility homeUtility;
#Test
public void testIsFilterWorkedTrue() {
homeService.getData();
}
HomeService.java
class HomeService {
#Autowired
private HomeUtility homeUtility;
public [RETURN_TYPE] getData() {
// call mocked method
output = mockedMethodcall();
test = homeUtility.callMethod(output);
return test;
}
}
In the above code, for homeUtility.callMethod(output);, I don't want it to be mocked and should go inside the method. I have to use
#Mock
private HomeUtility homeUtility;
because it is getting used in other methods as well. How can I ignore it
You can use thenCallRealMethod for ensuring the actual method is called for that object.
#InjectMock
private HomeService homeService;
#Mock
private HomeUtility homeUtility;
#Test
public void testIsFilterWorkedTrue() {
when( homeUtility.callMethod(anyString()).thenCallRealMethod() )
homeService.getData();
}
You can also use spy for this. Some more reading: https://www.javabullets.com/mockito-partial-mocks-mock-and-spy/

Mockito mocking objects from inside local method

In my class, dependencies are injected by Spring. During testing, I am using mocks. I am getting null pointer exception when I call sys.getId("abc12345") in the following code. I am wondering how to write a unit test that gets 100% coverage.
Class under test:
public class SystemUT implements SUTIface{
#Inject
private AccountLookupDAO dao;
#Inject
private OrchService service;
public Response perform(Request req){
String sellerId = getId(request.getSeller().getNum());
String buyerId = null;
if(req.getBuyerId){
buyerId = getId(request.getBuyer().getNum())
}
service.execute(Request,sellerId,buyerId)
}
String getId(String num){
PrefAcct prefAcctObj = dao.lookupPrefId(num,Consants.StrArr);
PrefSysOfRecObj sorObj= prefAcctObj.getSysOfRecord();
return sorObj.getId();
}
}
Unit test:
public Class SystemUTTest{
#Mock
SystemUT sys;
#Mock
AccountLookupDAO daoMock;
#Mock
OrchService serviceMock;
#Mock
PrefAcct prefAcctObj;
#Mock
PrefSysOfRecObj sorObj;
#Before
public void setup(){
Whitebox.setInternalState(sys, daoMock, serviceMock);
}
#Test
public test getId(){
when(dao.lookupPrefId(any(String.class), any(String[].class))).thenReturn(prefAcctObj);
when(prefAcctObj.getSysOfRecord()).thenReturn(sorObj);
when(sorObj.getId()).thenReturn("185");
assertEquals("185",sys.getId("abc12345"));
}
}
Your problem is that your SystemUT class doesn't have its dependencies injected. You could have Spring do this by using their JUnitRunner, but it's not really a unit test then, since you'd be letting Spring dictate which dependencies get injected. Really, you want to control them, and one way to do that is to transform your class to expose its dependencies via a constructor:
public class SystemUT implements SUTIface{
private final AccountLookupDAO dao;
private final OrchService service;
#Inject
public SystemUT(AccountLookupDAO dao, OrchService service) {
this.dao = dao;
this.service = service;
}
}
This will function identically to your current approach since Spring is able to inject dependencies using a constructor annotated with #Inject. Now, when you instantiate your SystemUT class for test, pass mocked objects for its dependencies:
#Mock
AccountLookupDAO daoMock;
#Mock
OrchService serviceMock;
private SystemUT sys;
#Before
public void setup(){
sys = new SystemUT(daoMock, serviceMock);
Whitebox.setInternalState(sys, daoMock, serviceMock);
}

Mockito - Creating nested mock objects

I'm learning Mockito. I am facing problem while creating mock for nested objects. See
public interface BaseManager {
public Query createQuery(String queryString);
}
and an implementation class for that
public class BaseManagerImpl implements BaseManager {
#Autowired
private SessionFactory sessionFactory;
// ...
}
Module level hibernate manager, for example:
public interface RegistrationManager {
#Transactional
public List<Country> getCountries();
}
and an implementation class for that
public class RegistrationManagerImpl implements RegistrationManager {
#Autowired
private BaseManager baseManager;
// ...
}
Now I'm facing problem in creating mocked base manager. My test class is:
public class MockitoTest {
private RegistrationManager registrationManager = new RegistrationManagerImpl();
#Mock private BaseManager baseManager;
#Mock private SessionFactory sessionFactory;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
// baseManager.setSessionFactory(sessionFactory);
registrationManager.setBaseManager(baseManager);
}
// ...
// #Test
}
Problem: sessionFactory is not instantiated inside baseManager.
Please help creating mock object. Thanks in advance!
The problem is that you are creating a mock of BaseManager but only BaseManagerImpl has a SessionFactory field. Mockito doesn't know about BaseManagerImpl. In your code you create two mocks which are completely independent of each other.
Unit tests are about testing an unit. So you should test BaseManagerImpl and RegistrationManagerImpl separately.
So you test BaseManagerImpl first:
public class BaseManagerImplTest {
private BaseManagerImpl target;
// ...
}
then you test RegistrationManagerImpl:
public class RegistrationManagerImplTest {
private RegistrationManagerImpl target;
// ...
}
I suggest that you should use the name target or something similar for your test target in your test class becaues it will make your code much more easier to read.
Another thing: If you test an object all of its dependencies should be mocked but you shouldn't care about the mocks' dependencies. You just mock their method invocations like:
Mockito.when(myMock.someMethod()).thenReturn(someResultObject);
You have to put the #InjectMocks annotation before class you want to test and mock the methods which are called by the basemanger or sessionFactory.
public class MockitoTest {
#InjectMocks
private RegistrationManager registrationManager = new RegistrationManagerImpl();
#Mock private BaseManager baseManager;
#Mock private SessionFactory sessionFactory;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
// baseManager.setSessionFactory(sessionFactory);
registrationManager.setBaseManager(baseManager);
Mockito.when(baseManager.yourMethod()).thenReturn(someObject);
}
// ...
// #Test
}
Hope this is it you're looking for!
You cannot inject a mock of SessionFactory into a mock of BaseManager.
As you are testing RegistrationManagerImpl, you just need to have a mock of BaseManager. You can use method stubbing so that the methods BaseManager will return the stubbed values when those methods are called from RegistrationManagerImpl methods. So, if you have a RegistrationManagerImpl as this:
public class RegistrationManagerImpl implements RegistrationManager {
#Autowired
private BaseManager baseManager;
// ...
public String doSomething(){
return baseManager.process();
}
}
you can write your MockitoTest as this:
public class MockitoTest {
#InjectMocks
private RegistrationManager registrationManager = new RegistrationManagerImpl();
#Mock private BaseManager baseManager;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
// ...
#Test
public void test() {
when(baseManager.process()).thenReturn("hello");
assertEquals("hello", registrationManager.doSomething());
}
}
And while testing BaseManager, there you need to use mock of SeesionFactory.

autowired dependency not getting mocked while executing test case with junit and mockito

I am using Junit4 and Mockito for test cases, in the following code dbprop.getProperty("config") is throwing a NullPointerException because dbProp is null. Please help me out why it was not mocked?
public abstract class BaseClass {
#Autowired
protected DBproperties dbprop;
}
public class SampleClass extends BaseClass {
#Autowired
private OrderService orderService;
valdiateOrder(String input) {
String config = dbprop.getProperty("config");
}
}
public class TestSampleClass {
#InjectMocks
SampleClass sampleClass;
#Mock
private OrderService orderService;
#Test
public void testValidateOrder() {
DBproperties dbprop = mock(DBproperties .class);
when(dbprop.getProperty("config")).thenReturn("xxxx");
assertNotNull(SampleClass.valdiateOrder("xxx"));
}
}
Your dbprop mock has not been injected into sampleClass, you need to add:
#Mock
private DBproperties dbprop;
Then remove the dbprop mock creation from your test method:
#Test
public void testValidateOrder() {
// DBproperties dbprop = mock(DBproperties .class); <-- removed
when(dbprop.getProperty("config")).thenReturn("xxxx");
assertNotNull(SampleClass.valdiateOrder("xxx"));
}
Next, to ensure mocks are injected when using the #InjectMocks annotations you need to either add the following runner:
#RunWith(MockitoJUnitRunner.class)
public class TestSampleClass {
...
Or call the following in a #Before method:
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
See the MockitoAnnotations and MockitoJUnitRunner JavaDocs for more information on the two approaches.
You can annotate your Object with #Mock, so its look like this
#Mock
DBproperties dbProperties;#Before public void init(){ MockitoAnnotations.initMocks(this);
}

Categories