No interactions with mock in unit test - java - java

I'm a bit new to mocking, but I have a class (lets call it ClassA) with methods including one that returns a put response after sending an item to a database.
This class is called in another class (lets say ClassB), but classB's methods do not return the response from ClassA.
Given the following structure for ClassA and ClassB:
private final DatabaseClientFactory dbClientFactory;
private final DatabaseClient dbClient;
... other instance vars ...
public ClassA() {
ClassA(new ..params, new dbClientFactory());
}
public ClassA(...some parameters ... DatabaseClientFactory dbClientFactory) {
....
this.dbClientFactory = dbClientFactory;
this.dbClient = this.dbClientFactory.get();
}
public PutResponse methodA() {
...
dbClient.put(...);
}
and ClassB:
public ClassB(...some params..., ClassA aClass) {
}
public void methodB() {
aClass.methodA();
...more random code
}
I've tried to set up the mock equivalent to this logic:
public class classBTest {
#Mock
private ClassA aClass = new ClassA();
private ClassB bClass;
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
bClass = spy(ClassB(aClass));
#Test
public void test() throws Exception {
bClass.methodB();
when(aClass.methodA(any())).thenReturn(PutResponse.newBuilder().build());
verify(aClass, Mockito.times(1)).methodA(any());
}
I kept getting an error that
Wanted but not invoked:
aClass.methodA(<any>);
Actually, there were zero interactions with this mock.
So I tried a few things
I tried changing the constructor call of bClass to be bClass = spy(ClassB(mock(ClassA.class)))
I tried adding when(classA.methodA(any())).thenReturn(PutResponse.newBuilder().build());
to the setUp method.
I tried setting up spy on an instance of ClassA, with mocked parameters
I tried using #InjectMocks but ended up with a null pointer exception.
But now I'm stuck
Any suggestions?
*Note that ClassA has an empty constructor by default

Related

Unable to inject mocks for my jersey project

I'm very new to writing unit tests for java. I want to write a test for method1:
public ClassA {
public String method1() {
ClassB classInst = ClassB.getInstance()
return classInst.doSomething()
}
}
Here, doSomething in classB connects to some databases and does an operation. This is my test class:
public TestClassA {
#Mock
private ClassB classBInst = mock(ClassB.class)
#InjectMocks
private ClassA classAInst = new ClassA()
#Before
public void setup() {
when(classInst.isClientEnabled()).thenReturn("ReturnStr");
}
#Test
public void testMethod1() {
String result = classAInst.method1();
assertEquals(result, "ReturnStr")
}
}
But the assert is failing because ClassB.doSomething() is not returning the mocked return value. Am I doing something wrong here? What is the correct way to mock classB here? I am using junit4 and mockito here

Mockito, object is not mocked

Here is the simple class I test. It looks strange but I have oversimplified it for a reason.
public class DishService {
DaoFactory daoFactory = DaoFactory.getInstance();
public void exampleMethod() {
System.out.println(daoFactory);
DishDao dishDao = daoFactory.createDishDao();
System.out.println(dishDao.findById(1));
}
}
And here is the DaoFactory class
public abstract class DaoFactory {
private static DaoFactory daoFactory;
public abstract UserDao createUserDao();
public abstract DishDao createDishDao();
public abstract OrderDao createOrderDao();
public static DaoFactory getInstance() {
if (daoFactory == null) {
synchronized (DaoFactory.class) {
daoFactory = new JDBCDaoFactory();
}
}
return daoFactory;
}
}
And here is my test class
#ExtendWith(MockitoExtension.class)
class DishServiceTest {
#Spy
DishService dishService;
#Mock
DishDao dishDao;
#Mock
DaoFactory daoFactory;
#Test
void example() {
MockedStatic<DaoFactory> daoFactoryDummy = Mockito.mockStatic(DaoFactory.class);
daoFactoryDummy.when(DaoFactory::getInstance).thenReturn(daoFactory);
Mockito.when(daoFactory.createDishDao()).thenReturn(dishDao);
when(dishDao.findById(1)).thenReturn(new Dish());
dishService.exampleMethod();
}
The problem is that daoFactory simply is not mocked. As you can see, I return new Dish ( default constructor ), so System.out.println() should show an empty object but it connects to DB and fetch object from real daoFactory.
And here is what I see in console
Dish{name='dadawd', description='wdadwad2', category=DRINKS, price=23131.00, imageFileName='FIRSTSnacksAsDaypart_1.jpg', orderItems=null}
Unnecessary stubbings detected.
-> at service.DishServiceTest.example(DishServiceTest.java:35)
-> at service.DishServiceTest.example(DishServiceTest.java:36)
35 and 36 lines of code you can see at the screen.
At which point do you initialize/create dishService object? In the #BeforeTest?
Since you have a field daoFactory on dishService object, DaoFactory.getInstance() gets called before you mock its methods, as it is called when you create dishService object.
So you need to create dishService object after you have mocked the Factory static methods, inside #Test method.
Or another way would be to use DaoFactory.getInstance() directly in the dishService.exampleMethod().
In both cases: first mock static method, then call it.
Also don't forget to close static mock, or even better: use it inside try-with-resources construct.

How to use #injectMocks thats requires constructor

I'm using mokito to inject a mock. This object extends a class that requires a contructor with arguments. How to mock this object that requires constructor arguments and pass this arguments as mock too?
Example class
public abstract class AbstractClassRequireContructor{
protected AbstractClassRequireContructor(Object param) {
}
public class ClassA extends AbstractClassRequireContructor{
public ClassA(Object param) {
super(param); // required by super class
}
}
Test class
#ExtendWith(MockitoExtension.class)
public class ClassATest{
#Mock
private Object paramMockToBeAddedByConstructor;
#InjectMocks
private ClassA classA; // requires contructor from super class
#BeforeEach
void setup{
when(paramMockToConstructor.anyMethod()).thenReturn(anyValue);
// how to inject mocked argument?
classA = new ClassA(paramMockToBeAddedByConstructor); // this doesn't work
}
#Test
void test(){
when(classA.anyMethod()).thenReturn(anyValue); // use injectMock class normally
}
}
Is there any another strategy to work arroung this better?
Drop the instantiation of a new ClassA object. It should work without it as follows:
#ExtendWith(MockitoExtension.class)
public class ClassATest{
#Mock
private Object paramMockToBeAddedByConstructor;
#InjectMocks
private ClassA classA;
#BeforeEach
void setup{
when(paramMockToConstructor.anyMethod()).thenReturn(anyValue);
}
#Test
void test(){
when(classA.anyMethod()).thenReturn(anyValue);
}
}

How can we mock a response from another class using Mockito while unit testing

I have a method to test which is calling another class to get some information:
public ClassToTest {
public void methodToTest() {
AnotherClass ac = Factory.getInstance();
ResponseObj response = ac.anotherMethod();
}
}
AnotherClass is part of another JAR and I would like to mock the response from it(to be specific mock ResponseObj response)
How can I achieve that using Mockito?
First you need is to make your class testable. It means you need to extract object creation (AnotherClass ac = Factory.getInstance()) from your methodToTest to instance field or maybe separate method (to be able to mock it), or even better - create object outside of your class and pass it via constructor. As a result, your class under test should look like:
public class ClassToTest {
private AnotherClass ac;
public ClassToTest(AnotherClass ac) {
this.ac = ac;
}
public void methodToTest() {
ResponseObj response = ac.anotherMethod();
response.smth();
}
}
Then you need to declare AnotherClass and ResponseObj as fields in test class, and initialize them as a mocks.
AnotherClass ac = Mockito.mock(AnotherClass.class);
ResponseObj responseMock = Mockito.mock(ResponseObj.class);
After that you can mock method call:
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
At the end your test class should look like:
public class ClassToTestTest {
private AnotherClass anotherClassMock = mock(AnotherClass.class);
private ResponseObj responseMock = mock(ResponseObj.class);
private ClassToTest classToTest = new ClassToTest(anotherClassMock);
#Test
public void test() {
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
classToTest.methodToTest();
verify(responseMock, only()).smth();
}
}
And in case you couldn't change public API of your ClassToTest, you can use approach with Mockito spy and protected method.
public class ClassToTest {
public void methodToTest() {
AnotherClass ac = constructAnotherClassObj();
ResponseObj response = ac.anotherMethod();
response.smth();
}
protected AnotherClass constructAnotherClassObj() {
return Factory.getInstance();
}
}
public class ClassToTestTest {
private AnotherClass anotherClassMock = mock(AnotherClass.class);
private ResponseObj responseMock = mock(ResponseObj.class);
private ClassToTest classToTest = spy(new ClassToTest());
#Test
public void test() {
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
when(classToTest.constructAnotherClassObj()).thenReturn(anotherClassMock);
classToTest.methodToTest();
verify(responseMock, only()).smth();
}
}
Although the answer by #arsen_adzhiametov is correct and up to the mark I would like to contribute how I do it.
In this case, I am mocking the value of HomeClient which internally is a WebClient that calls out another service for some values.
TestClass.java (Please name it better)
...
import org.mockito.Mockito;
...
class TestClass {
HomeClient mockHomeClient;
#BeforeEach
void setup() {
mockHomeClient = Mockito.mock(HomeClient.class);
// Axon specific test code. Can ignore if not using Axon.
fixture = new AggregateTestFixture<>(SomeAgreegate.class);
fixture.registerInjectableResource(mockHomeClient);
}
#Test
void testOpenOperation() throws HomeClientException {
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(2);
// Do what you will with your code and call the method which you want to test
// Mockito will mock the `HomeClient` in this case and `getXYZ` will return `2`
// You can also change the mock response any time in the same function
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(-100);
// Or specify different results on mock when different values are provided
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(1);
Mockito.when(mockHomeClient.getXYZ("foo")).thenReturn(100);
Mockito.when(mockHomeClient.getXYZ("bar")).thenReturn(0);
}
}

#Autowired dependencies is not getting initialized in base class

I have a test class which is testing an other class method
Other class is structured like this
#Component
public abstract class ParentOpManager{
#Autowired
private ProcessorRequestWrapper processorRequestWrapper;
#Autowired
private XYProcessor xyProcessor;
}
#Component("childManager")
public class ChildOperationManager extends ParentOpManager{
}
public abstract class ParentClass{
protected final RequestWrapper requestWrapper;
protected final ParentOpManager parentOpManager;
public ParentClass(final RequestWrapper requestWrapper, final ParentOpManager parentOpManager){
this.requestWrapper = requestWrapper;
this.parentOpManager = parentOpManager;
}
}
further I have, child classes extending this class
public class ChildClass extends ParentClass{
#Autowired
private NinjaManager ninjaManager;
#Autowired
public ChildClass(final RequestWrapper requestWrapper, #Qualifier("childManager")final ParentOpManager parentOpManager){
super(requestWrapper, parentOpManager);
}
public void methodA() throws Exception {
Request item = requestWrapper.findItem(); // Problem place 1
}
public void methodB() throws Exception {
Request item = ninjaManager.findItem(); // Problem place 2
}
}
I need to test methods of ChildClass. For this I have written a test class.
//#RunWith(MockitoJunitRunner.class)
//#ContextConfiguration
public class TestClass{
#Mock
ChildOperationManager chOpManager;
#Mock
RequestWrapper requestWrapper;
#InjectMocks
ChildClass childObject;
#Before
public void setup(){
MockitoAnnotations.initMocks(this);
}
#Test
public void testSomeMethodA() throws Exception{
childObject.methodA();
}
}
So, the problem is when I am class methodA from test class, requestWrapper is NULL. I can not understand why this is happening ?
EDIT:
If i do like
#Mock
ChildOperationManager chOpManager = new ChildOperationManager();
#Mock
RequestWrapper requestWrapper;
#InjectMocks
ChildClass childObject = new childObject(requestWrapper, chOpManager);
Problem seams to be resolved. There is some other problem which might be some permission issue. But do you think doing this way is good approach ?
Your error is this:
#Autowired
public ChildClass(final RequestWrapper requestWrapper, #Qualifier("childManager")final ParentOpManager parentOpManager){
super(requestWrapper, parentOpManager);
}
public void methodA() throws Exception {
Request item = requestWrapper.findItem(); // this requestWrapper is null
}
You don't assign the requestWrapper reference in the child. So it remains null.
You should just remove the member variable requestWrapper and parentOpManager from the child. this way, you'll use the parent's one, which is initialized.
Problem is that Mockito tried to inject mock via constructor in first step.
public class DefaultInjectionEngine {
public void injectMocksOnFields(Set<Field> needingInjection, Set<Object> mocks, Object testClassInstance) {
MockInjection.onFields(needingInjection, testClassInstance)
.withMocks(mocks)
.tryConstructorInjection() <-- Here
.tryPropertyOrFieldInjection()
.handleSpyAnnotation()
.apply();
}
}
And if it found proper constructor, it doesn't try to inject mocks via property or field.
In your case you have constructor for ChildClass, which was picked by Mockito, but you don't initialize a fields in ChildClass.
As workaround, you can resolve it in this way (just don't use mockito injections):
RequestWrapper wrapper;
ChildOperationManager childOperationManager;
ChildClass childObject;
#Before
public void setUp() {
wrapper = Mockito.mock(RequestWrapper.class);
childOperationManager = Mockito.mock(ChildOperationManager.class);
childObject = new ChildClass(wrapper, childOperationManager );
}

Categories

Resources