java - Mockito/Spy 不工作,执行原始功能
问题描述
我正在上课:
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 调用,直接更新数据库。现在我想单独模拟这两个函数,这样每当我的测试函数运行时,它应该返回 true。
我写了我的测试功能如下:
@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());
}
但是当我运行测试类时,它执行实际的功能,模拟不起作用。有人可以帮我解决这个问题吗?
提前致谢!
解决方案
Mockito 通过在 mock 下创建类的CGLIB代理来工作。例如,如果你mock(MyClass.class)
,你会得到一个类的动态代理MyClass$$EnhancedByMockito$$.class
,它扩展了MyClass.class
。由于代理是 的子类MyClass
,因此生成的类允许用户覆盖特定功能(“模拟”它)。大多数方法拦截都通过易于使用的语句为您隐藏在幕后,例如when
.
不幸的是,由于 Java 的限制,无法使用本地反射代理内部方法调用。这是因为,如果您直接MyClass:b
从实例方法调用实例方法,则插入一个扩展为间接执行MyClass::a
的代理类是没有间隙的。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 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
}
}
推荐阅读
- javascript - 在while循环中迭代时从数组中删除元素
- javascript - JavaScript try 块中的对象字面量
- sql - 当日期在 SQL 中另一个数据集中的日期范围内时合并
- android - 如何指向特定的 RecyclerView onClick 视图(Android Java)?
- c# - 通过参数从进程中获取退出代码
- javascript - 如何重建数组中的对象数组
- java - OptaPlanner 8.0.0 final (Windows 10) 中的课程时间表和会议安排示例被破坏
- django - 如果用户是管理员 django rest,则将字段添加到序列化程序
- python - 测试数据帧是否被洗牌
- javascript - 节点,Sqlite { stmt:语句 { stmt:未定义},lastID:0,更改:1 }