Mocks not getting invoked with static members using PowerMockito - java

I am trying to mock an Impl that contains 2 static members A, B, and a static method Utils.SomeMethod. I tried to mix PowerMock and Mockito initially but was not sure if this was causing the problem so I changed all refs to PowerMockito. I get unit test failures that mocks are not getting invoked. if I remove statics and just use Mockito then all tests succeed.
Here is a brief outline of the problem.
class Impl {
static A a;
static B b;
private static final String s = Utils.SomeMethod();
void mainMethod() {
a.aMethod("foo");
b.bMethod("bar");
}
}
So in my unit test I have
#PowerMockIgnore({"javax.net.ssl.*" , "javax.crypto.*"})
#RunWith(PowerMockRunner.class)
#PrepareForTest({Utils.class})
public class ImplTest {
A a;
B b;
#Captor
ArgumentCaptor<String> argumentCaptor;
#BeforeClass
static public void setUp() {
PowerMockito.mockStatic(Utils.class);
PowerMockito.when(Utils.SomeMethod()).thenReturn("test"); // works
}
#Before
public void before() {
a = PowerMockito.mock(A.class);
b = PowerMockito.mock(B.class);
impl = PowerMockito.mock(Impl.class);
impl.setA(a); // I tried #Mock and #InjectMocks but seemed to not work on statics, works with non static members
impl.setB(b);
}
#Test
public void test() {
PowerMockito.when(a
.aMethod(any(String.class))
.thenReturn("hmm");
PowerMockito.when(b.bMethod(any(String.class))
.thenReturn("yo");
impl.mainMethod();
verify(a, times(1)).aMethod(argumentCaptor.capture());
// fails that 0 times mock was invoked
}
}

As I can see it you are mocking Impl but you should instantiate it if you want mainMethod invoke your static methods.
Also, are you initializing argumentCaptor somewhere in your code?

I'd like to suggest using Mockito for most testing mocks, and using PowerMockito only when dealing with some static methods. With slight changes, your test code worked ok:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ Utils.class })
public class ImplTest {
#Mock
A a;
#Mock
B b;
#Captor
ArgumentCaptor<String> argumentCaptor;
#BeforeClass
static public void setUp() {
PowerMockito.mockStatic(Utils.class);
Mockito.when(Utils.SomeMethod()).thenReturn("test"); // works
}
Impl impl;
#Before
public void before() {
Impl.setA(a);
Impl.setB(b);
impl = new Impl();
}
#Test
public void test() {
Mockito
.when(a.aMethod(Matchers.any(String.class)))
.thenReturn("hmmm");
Mockito
.when(b.bMethod(Matchers.any(String.class)))
.thenReturn("yo");
impl.mainMethod();
Mockito.verify(a, Mockito.times(1)).aMethod(argumentCaptor.capture());
Assert.assertEquals("foo", argumentCaptor.getValue());
Mockito.verify(b, Mockito.times(1)).bMethod(argumentCaptor.capture());
Assert.assertEquals("bar", argumentCaptor.getValue());
}
}
Please notice that if A and B are defined as static, they should be injected into the class, not into individual instance(s).
#InjectMocks will not work in this context, since it requires a different Runner. Please have a look at this other article Difference between #Mock and #InjectMocks

Related

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/

Injecting beans in a JUnit/Mockito test returns zero

I have a JavaEE application with Stateless EJBs that I use for business logic (EjbBusiness) and database access (EjbDAO). I need to run a unit test on EjbBusiness, but the DAO method always returns zero.
In the example below I have both classes and the unit test. I mock the EjbDAO method that connects to the database, to return a testing SQL connection:
#Stateless
public class EjbDAO {
public Connection getConnFromPool() {
Connection conn = null; // in production this would return a connection
return conn;
}
public int add2(int i) {
Connection conn = getConnFromPool();
System.out.println("in EjbDAO: " + i);
return i + 2;
}
}
#Stateless
public class EjbBusiness {
#Inject
private EjbDAO dao;
public int add2(int i) {
int j = dao.add2(i);
System.out.println("in EjbBusiness: " + j);
return j;
}
}
Since I mock one of the methods of EjbDAO, I annotate it with #Spy in UnitTest:
#RunWith(MockitoJUnitRunner.class)
public class UnitTest {
#InjectMocks
private EjbBusiness biz;
#InjectMocks
#Spy
private EjbDAO dao;
#Before
public void setup() {
dao = Mockito.mock(EjbDAO.class);
biz = Mockito.mock(EjbBusiness.class);
MockitoAnnotations.initMocks(this);
}
#Test
public void testBean() {
// this would return the testing connection
Mockito.doReturn(null).when(dao).getConnFromPool();
int i = biz.add2(3);
assertThat(5).isEqualTo(i);
}
}
Problem is that the assertion doesn't work, as biz.add2(3) returns zero instead of 5. Also, the System.out.println in both beans is not printed. How to declare/mock the beans for the test to work?
Use #InjectMocks only when you calling actual method otherwise don't use it. And also don't use #InjectMocks and Mockito.mock() or #Mock together.
In your code you are using #InjectMocks on dao object and you are also creatign mock for that. And use Mockito.mock() when you want to stub the method calls instead of calling actual methods.
System.out.println() is not working in your code because you created mocks for objects biz and dao. Actual methods (i.e add2() because of this you are getting 0 as output) not executed when you call with mock objects.
For more info on when to use #InjectMocks refer
this
#RunWith(MockitoJUnitRunner.class)
public class UnitTest {
#InjectMocks
private EjbBusiness biz;
#Mock
private EjbDAO dao;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testBean() {
// this would return the testing connection
Mockito.doReturn(null).when(dao).getConnFromPool();
Mockito.doCallRealMethod().when(dao).add2(Mockito.anyInt());
int i = biz.add2(3);
assertThat(i).isEqualTo(5);
}
}
You should not use one unit test to test both classes.
You should have two test classes to test them.
For Example,
#RunWith(MockitoJUnitRunner.class)
public class EjbBusinessTest {
#InjectMocks
private EjbBusiness biz;
#Mock
private EjbDAO dao;
#Test
public void testAdd2() {
// this would return the testing connection
Mockito.doReturn(null).when(dao).getConnFromPool();
Mockito.doReturn(5).when(dao).add2();
int i = biz.add2(3);
assertThat(5).isEqualTo(i);
}
}
In the above class we are testing only the method EjbBusinessTest.add2 and we don't care what happens or if the method EjbDAO.add2 is working properly. In this all we should care is whether the method under test is working properly, hence we mock everything external to that method.
Following a similar approach for EjbDAO.add2 as well, The test case should look like something given below. I have also made the method EjbDAO.getConnection private so that that should also be included in the test. This choice should be made by you if you need to make it private or public. If you decide to keep it public then you should use #Spy on EjbDAO and mock the EjbDAO.getConnection method.
#RunWith(MockitoJUnitRunner.class)
public class EjbDAOTest {
//instantiate this object the way you want. Mock the external objects used inside this like the library used to get connection inside EjbDAO.getConnection() Method
#InjectMocks
private EjbDAO dao;
#Test
public void testAdd2() {
// I would suggest you to make the getConnection method private.
// do not mock the getConnection here, instead mock how you are getting the connection inside the getConnection method.
int i = dao.add2(3);
assertThat(5).isEqualTo(i);
}
}
Hope it helps.

Is there any way to Mock the private method , which is there in other class

As per my knowledge, We can Mock the private method in same class by using PowerMockito.
With in the same class is working fine for me , but when i'm calling private method from the other class it's not working.
Below Example i've 2 classes , Service class and Helper classes
Helper class having private method.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ Helper.class,Service.class })
#PowerMockIgnore("javax.management.*")
public class EPartnerBatchServiceTest {
private Helper helper;
#InjectMocks
private ServiceClass serviceClass;
#Before
public void setUp() throws Exception {
helper = PowerMockito.spy(new Helper());
ServiceClass = PowerMockito.spy(new serviceClass());
MockitoAnnotations.initMocks(this);
}
#Test
public void testUpdateIndividualUserStatus() throws Exception {
PowerMockito.doReturn("Test").when(helper, "privateMethod", anyString(), Matchers.anyObject());
String response = serviceClass.update(loggerId, activityLogDTO);
}
}
Sample Classes :
Class A{
value=new B().method1();
}
Class B{
public method1(){
value = method2();
}
private method2(){
return "Test";
}
}
You shouldn't be worrying with testing explicitly your private methods, since they are not accessible for the ones calling it, it's function should be tested somewhere in the flow of your public methods. But, if for some reason you need to test them explicitly, then maybe reflections and setting those methods as accessible for testing may resolve your problem.
You'll find great examples here: https://www.baeldung.com/java-method-reflection

Mockito - Calling real methods during When - ThenReturn clause

Consider the following class (using CDI + a cutstom Restclient)
public class A {
#Inject
Restclient client;
public Object init(String token) {
String b = createB(token);
return c(b);
}
public String createB(String token)
return client.getB(token);
}
public Object c(String b) {
return new C(b);
}
}
I want to mock the method createB(token), as I don't want to test the Rest Client. So I've done the following:
public class TestA {
#Mock
A a;
#Test
public void testA() {
when (a.createB("123")).thenReturn("FakeB");
Object c = a.init("123");
assertNotNull(c); // Fails
}
}
For some reason this JUnit 4 + Mockito 2.18 test fails as 'c' is null but my methods are correctly working (have tested them).
If I use #Spy for A, I get a NPE because my Restclient is not initialized (even if I add #Mock RestClient client) and the when(...).thenReturn(...) actually calls the real method...
No clue how to fix this even if it feels so simple...
If you want to avoid method invocations during stubbing, please use the following notation:
doXxx(...).when(spyObject).method();
So, in your case this will work:
public void test_a() {
...
doReturn("FakeB").when(restClient).getB("token"));
assertNotNull(a.init("token"))
}
Use #Mock in combination with #InjectMocks.
#RunWith(MockitoJUnitRunner.class)
public class TestA {
#Mock
RestClient restClient;
#InjectMocks
A a;
public void test_a() {
...
when(restClient.getB("token")).thenReturn("FakeB")
assertNotNull(a.init("token"))
}
}
However you must allow your A class to have a RestClient injected, e.g.
public class A {
final Restclient restClient;
#Inject
public A(final RestClient restClient) {
this.restClient = restClient;
}
...
Which, to be honest, is the optimal way to deal with dependencies (and use CDI).

Mockito Not Able to Mock function call present in target class's constructor

I am trying to test the following class using Mockito and JUnit :
public class A {
private SomeClass someObject;
private SomeImpClass someImpObject1;
private SomeImpClass2 someImpObject2;
public A(SomeImpClass someImpObject1, SomeImpClass2 someImpObject2){
someObject = makeNewObject(someImpObject1, someImpObject2);
}
public makeNewObject(SomeImpClass1 someImpObject1, SomeImpClass2 someImpObject2){
return new SomeObject(someImpObject1,someImpObject2);
}
public usingSomeObject(){
someObject.doSomething();
}
}
So, I wrote a Unit Test using Mockito and JUnit :
#RunWith(MockitoJUnitRunner.class)
public class ATest {
#Mock
SomeImpClass1 someImpObject1;
#Mock
SomeImpClass2 someImpObject2;
#Mock
SomeObject someObject;
#Spy
A a;
#Before
public void setUp() {
when(A.makeNewObject).thenReturn(someObject);
this.A = new A(this.someImpObject1, someImpObject2);
when(someObject.doSomething).thenReturn(something);
}
}
The Issue I am facing here is, although I have stubbed the function makeNewObject to return a Mocked object of SomeClass, the code flow is still going inside the fucntion (makeNewObject) and giving a null exception.
What Am I Doing Wrong ?
I have wasted a day behind this.
Not Very Fluent with Mockito.
You wont be able to achieve what you are aiming for with spying and stubbing.
This is because your aiming at stubbing a method used in a constructor.. but you cannot start stubbing once you created a concrete object and spy it.. can't be done..
I would suggest creating a private class inside the test class which extends your class under test, override the method invoked in the constructor and then use it in your tests:
#RunWith(MockitoJUnitRunner.class)
public class ATest {
#Mock
SomeObject someObjectMock;
A a;
#Before
public void setUp() {
this.a = new MyTest();
}
private class MyTest extends ATest{
#Override
public makeNewObject(SomeImpClass1 someImpObject1, SomeImpClass2 someImpObject2){
return someObjectMock;
}
}
Now you dont need to use spying and stubbing of it also as the overriden method is always returning what you expect in the test.

Categories