I am having a class :
GP_CategoryService.java Function -->
public JSONObject deleteCategory(GP_CategorySubcategoryBean bean) {
JSONObject data = new JSONObject();
DirectoryCategoryMaster oCategory = getCategoryMaster(bean);
if (oCategory.getDirCategoryId() != null) {
boolean isDeleted = delete(oCategory);
data.put(ConstantUtil.STATUS, ConstantUtil.SUCCESS);
data.put(ConstantUtil.DATA, "Category deleted successfully");
}
}
I have 2 inner function calls :
These are basically DAO calls, updating the Database directly. Now I want to mock these 2 fucntions alone such that whenever my test function is running, it should return true.
I have written my test function as below :
@Test
public void deleteCategoryTestDAOV() {
JSONObject expected = new JSONObject();
expected.put(ConstantUtil.STATUS, ConstantUtil.SUCCESS);
expected.put(ConstantUtil.DATA, "Category deleted successfully");
bean.setCategoryId(1);
bean.setCategoryName("Test");
DirectoryCategoryMaster master=new DirectoryCategoryMaster();
master.setDirCategoryId(1);
GP_CategoryService mock = spy(new GP_CategoryService());
when(mock.delete(master)).thenReturn(true);
when(mock.getCategoryMaster(bean)).thenReturn(master);
JSONObject actual=new JSONObject();
actual=mock.deleteCategory(bean);
assertEquals(expected.toJSONString(), actual.toJSONString());
}
But when I am running the test class, its executing the actual fucntion, mock is not working. Can anhyone please help me to resolve this issue?
Thanks in advance!
Mockito works by creating a CGLIB proxy of the class under mock. For example, if you mock(MyClass.class)
, you will get a dynamic proxy of class MyClass$$EnhancedByMockito$$.class
, which extends MyClass.class
. Since the proxy is a subclass of MyClass
, the resulting class allows the user to override specific functionality ("mock" it). Most of the method interception is hidden behind the scenes for you by easy-to-use statements like when
.
Unfortunately, due to limitations in Java, it is not possible to proxy internal method calls with native reflection. This is because, if you're directly calling instance method MyClass:b
from instance method MyClass::a
, there is no gap to insert a proxy class which extends MyClass
to execute MyClass::b
indirectly.
Technically, it's possible to do this with some really advanced bytecode manipulation (with something like ByteBuddy).
Example that does not work:
class MyClass {
public String doSomething() {
return doSomethingElse();
}
public String doSomethingElse() {
return "foo";
}
}
// ...
class MyTest {
private MyClass myClass;
// ...
@Test
void myTest() {
when(myClass.doSomethingElse()).thenReturn("Bar");
assertEquals("bar", myClass.doSomething()); // FAILS
}
}
Example that does work, using an intermediate class with overrideable methods:
class MyClass {
private MyClassBackend myClassBackend;
public MyClass(MyClassBackend myClassBackend) {
this.myClassBackend = myClassBackend;
}
public String doSomething() {
return myClassBackend.doSomethingElse();
}
}
class MyClassBackend {
public String doSomethingElse() {
return "foo";
}
}
// ...
class MyTest {
private MyClass myClass;
@Mock
private MyClassBackend myClassBackend;
@BeforeEach
void setUp() {
this.myClass = new MyClass(myClassBackend);
}
// ...
@Test
void myTest() {
when(myClassBackend.doSomethingElse()).thenReturn("bar");
assertEquals("bar", myClass.doSomething()); // PASSES
}
}