Mockito/Spy 不工作,正在执行原始功能
Mockito/Spy not working, executing the original function
我有 class :
GP_CategoryService.java
函数 -->
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");
}
}
我有 2 个内部函数调用:
- getCategoryMaster(bean)
- 删除(o类别)
这些基本上是 DAO 调用,直接更新数据库。
现在我想单独模拟这两个函数,这样只要我的测试函数是 运行,它就应该 return 为真。
我的测试函数如下:
@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());
}
但是当我 运行 测试 class 时,它执行实际的功能,mock 不工作。 anhyone 可以帮我解决这个问题吗?
提前致谢!
Mockito 通过在 mock 下创建 class 的 CGLIB 代理来工作。例如,如果您 mock(MyClass.class)
,您将获得 class MyClass$$EnhancedByMockito$$.class
的动态代理,它扩展了 MyClass.class
。由于代理是 MyClass
的子 class,由此产生的 class 允许用户覆盖特定功能(“模拟”它)。通过像 when
.
这样易于使用的语句,大部分方法拦截都隐藏在幕后。
遗憾的是,由于 Java 中的限制,无法使用本机反射来代理内部方法调用。这是因为,如果您直接从实例方法 MyClass::a
调用实例方法 MyClass:b
,则没有插入代理 class 的间隙,该代理 class 扩展 MyClass
以执行 MyClass::b
间接地。
从技术上讲,可以通过一些非常高级的字节码操作(如 ByteBuddy)来做到这一点。
无效示例:
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
}
}
确实有效的示例,使用具有可覆盖方法的中间 class:
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
}
}
我有 class :
GP_CategoryService.java 函数 -->
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");
}
}
我有 2 个内部函数调用:
- getCategoryMaster(bean)
- 删除(o类别)
这些基本上是 DAO 调用,直接更新数据库。 现在我想单独模拟这两个函数,这样只要我的测试函数是 运行,它就应该 return 为真。
我的测试函数如下:
@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());
}
但是当我 运行 测试 class 时,它执行实际的功能,mock 不工作。 anhyone 可以帮我解决这个问题吗?
提前致谢!
Mockito 通过在 mock 下创建 class 的 CGLIB 代理来工作。例如,如果您 mock(MyClass.class)
,您将获得 class MyClass$$EnhancedByMockito$$.class
的动态代理,它扩展了 MyClass.class
。由于代理是 MyClass
的子 class,由此产生的 class 允许用户覆盖特定功能(“模拟”它)。通过像 when
.
遗憾的是,由于 Java 中的限制,无法使用本机反射来代理内部方法调用。这是因为,如果您直接从实例方法 MyClass::a
调用实例方法 MyClass:b
,则没有插入代理 class 的间隙,该代理 class 扩展 MyClass
以执行 MyClass::b
间接地。
从技术上讲,可以通过一些非常高级的字节码操作(如 ByteBuddy)来做到这一点。
无效示例:
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
}
}
确实有效的示例,使用具有可覆盖方法的中间 class:
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
}
}