在 Mockito 中检测到未完成的存根

2023-12-11

我在运行测试时遇到以下异常。我正在使用 Mockito 进行嘲笑。 Mockito 库提到的提示没有帮助。

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
    -> at com.a.b.DomainTestFactory.myTest(DomainTestFactory.java:355)

    E.g. thenReturn() may be missing.
    Examples of correct stubbing:
        when(mock.isOk()).thenReturn(true);
        when(mock.isOk()).thenThrow(exception);
        doThrow(exception).when(mock).someVoidMethod();
    Hints:
     1. missing thenReturn()
     2. you are trying to stub a final method, you naughty developer!

        at a.b.DomainTestFactory.myTest(DomainTestFactory.java:276)
        ..........

测试代码来自DomainTestFactory。当我运行以下测试时,我看到了异常。

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    Mockito.when(mainModel.getList()).thenReturn(getSomeList()); // Line 355
}

private List<SomeModel> getSomeList() {
    SomeModel model = Mockito.mock(SomeModel.class);
    Mockito.when(model.getName()).thenReturn("SomeName"); // Line 276
    Mockito.when(model.getAddress()).thenReturn("Address");
    return Arrays.asList(model);
}

public class SomeModel extends SomeInputModel{
    protected String address;
    protected List<SomeClass> properties;

    public SomeModel() {
        this.Properties = new java.util.ArrayList<SomeClass>(); 
    }

    public String getAddress() {
        return this.address;
    }

}

public class SomeInputModel{

    public NetworkInputModel() {
        this.Properties = new java.util.ArrayList<SomeClass>(); 
    }

    protected String Name;
    protected List<SomeClass> properties;

    public String getName() {
        return this.Name;
    }

    public void setName(String value) {
        this.Name = value;
    }
}

你将嘲笑嵌套在嘲笑之中。你正在呼唤getSomeList(),在你完成嘲笑之前,它会进行一些嘲笑MyMainModel。 Mockito 不喜欢你这样做。

Replace

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355
}

with

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    List<SomeModel> someModelList = getSomeList();
    Mockito.when(mainModel.getList()).thenReturn(someModelList);
}

要理解为什么这会导致问题,您需要了解一些 Mockito 的工作原理,并且还要了解 Java 中表达式和语句的求值顺序。

Mockito 无法读取您的源代码,因此为了弄清楚您要求它做什么,它在很大程度上依赖于静态。当您调用模拟对象上的方法时,Mockito 会在内部调用列表中记录调用的详细信息。这when方法从列表中读取最后一个调用并将该调用记录在OngoingStubbing它返回的对象。

The line

Mockito.when(mainModel.getList()).thenReturn(someModelList);

导致与 Mockito 发生以下交互:

  • 模拟方法mainModel.getList()叫做,
  • 静态方法when叫做,
  • Method thenReturn被称为OngoingStubbing返回的对象when method.

The thenReturn然后方法可以指示它通过接收到的模拟OngoingStubbing方法来处理任何合适的调用getList返回方法someModelList.

事实上,由于 Mockito 看不到你的代码,你也可以编写你的模拟,如下所示:

mainModel.getList();
Mockito.when((List<SomeModel>)null).thenReturn(someModelList);

这种风格阅读起来有些不太清晰,特别是在这种情况下null必须进行强制转换,但它会生成与 Mockito 相同的交互序列,并且将实现与上面的行相同的结果。

然而,该行

Mockito.when(mainModel.getList()).thenReturn(getSomeList());

导致与 Mockito 发生以下交互:

  1. 模拟方法mainModel.getList()叫做,
  2. 静态方法when叫做,
  3. A new mock of SomeModel已创建(内部getSomeList()),
  4. 模拟方法model.getName()叫做,

此时 Mockito 感到困惑。它以为你在嘲笑mainModel.getList(),但现在你告诉它你想嘲笑model.getName()方法。对于 Mockito,您似乎正在执行以下操作:

when(mainModel.getList());
// ...
when(model.getName()).thenReturn(...);

这看起来很愚蠢Mockito因为它不能确定你在做什么mainModel.getList().

请注意,我们没有到达thenReturn方法调用,因为 JVM 需要先评估该方法的参数,然后才能调用该方法。在这种情况下,这意味着调用getSomeList() method.

一般来说,像 Mockito 那样依赖静态是一个糟糕的设计决策,因为它可能导致违反最小惊讶原则的情况。然而,Mockito 的设计确实可以实现清晰且富有表现力的嘲笑,即使有时会让人感到惊讶。

最后,最新版本的 Mockito 在上面的错误消息中添加了一行额外的内容。这条额外的行表明您可能处于与此问题相同的情况:

3:如果完成,您将在“thenReturn”指令之前对另一个模拟的行为进行存根

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Mockito 中检测到未完成的存根 的相关文章

随机推荐

  • 在 d3.js 中显示圆弧末端的文本

    经过一整天的煎熬我的大脑 最后决定来这里问问 我正在尝试在 d3 js 中的圆弧末尾附加文本 我尝试使用 arc cenriod 但这将文本保留在圆弧的中心 我想在圆弧末尾显示文本 var pi Math PI width 600 heig
  • 以管理员身份运行 BAT(无快捷方式)

    因此 我试图创建一个 bat 来任务杀死 Win7 中的特定程序 我正在使用命令 taskkill f im LCore exe bat 需要以管理员身份运行才能工作 因此我创建了一个快捷方式 以便按照另一个线程中指定的方式在管理员模式下自
  • LMAX 的颠覆者模式如何运作?

    我正在尝试理解破坏者模式 我观看了 InfoQ 视频并尝试阅读他们的论文 我知道涉及一个环形缓冲区 它被初始化为一个非常大的数组 以利用缓存局部性 消除新内存的分配 听起来好像有一个或多个原子整数来跟踪位置 每个 事件 似乎都有一个唯一的
  • Greasemonkey Jquery 干扰? [复制]

    这个问题在这里已经有答案了 可能的重复 Greasemonkey 1 0 中的 jQuery 与使用 jQuery 的网站发生冲突 看来 如果我的任何 Greasemonkey 脚本具有如下所示的行 我会在包含 jquery 的网站上收到错
  • 用 sed 替换第一次出现的匹配项

    我正在用 sed 进行查找和替换 替换 BASH 变量 a 当在新行的开头时 与 BASH 变量 b sed i s a b file txt 这将替换所有匹配项 a 如何仅替换第一次出现的 a在整个文件中 一种方式使用sed sed s
  • 正则表达式:忽略字符串的一部分

    我需要一个忽略字符串一部分的正则表达式 example 盲注 100 200 锦标赛 2020202220 盲注 100 200 底注 20 锦标赛 2020202220 我正在使用这个表达 Blinds s 100 d s Ante s
  • 将构建工具更新到 22.6 后,无法创建 AVD 或使用 AVD 测试任何应用程序

    更新后SDK Build Tools to 22 6 and ADT Plugin无法创建 AVD 或通过任何模拟器启动任何应用程序 那些在更新之前创建的应用程序 没有错误消息显示在console or in log cat 所以无法跟踪问
  • 使用谷歌地图 API 将当前 GPS 坐标发送到 mySQL 数据库

    我正在尝试在 jquery 中构建一个高尔夫应用程序 我可以使用按钮将当前的 GPS 坐标发送到 mySQL 数据库 问题是我是 php 新手 我正在尝试找到我可以使用的代码 我建了一个数据库 ID int 3 自增 经纬度浮动 10 LO
  • 打开/操作目录中的所有文件的最有效方法是什么?

    我需要对目录的所有文件执行脚本 搜索 以下是有效的方法 我只是问哪个最好 我需要以下形式的文件名 parsedchpt31 4 txt Glob my parse corpus for all options glob only if al
  • C++ Regex POSIX 字符类出现问题

    我正在尝试创建一个能够分析如下内容的正则表达式 002561 1415179671591i jpg 第二部分是 unix 时间戳 在 i 之前 我需要提取它 我想出了以下语法 但是 std regex 在我检查匹配之前一直抛出 regex
  • 从 cloudfoundry 任务命令访问 java 可执行文件(cf run-task)

    我需要 java 可执行文件来运行 java jarCloudFoundry任务命令 这是我尝试运行任务的方法 cf run task bignibou batch java jar bignibou batch build libs bi
  • java.lang.NoClassDefFoundError:jdk/nashorn/api/scripting/NashornScriptEngineFactory

    我想在 1 16 3 中编写 Minecraft mod 我已经在1 12 2中制作了一个mod 但我没有遇到这个问题 我只是下载 1 16 3 forge Mdk 并为 eclipse 构建它 在 cmd 中使用 gradlew ecli
  • 如何更改 Blazor 中“body”元素的 CSS 或类

    我目前正在制作一个 更改主题 按钮 以便我可以在 深色模式 和 浅色模式 之间切换整个页面 但我找不到改变整个页面背景颜色的方法 基本上 我需要改变风格 这是我能想到的唯一方法 我的想法是 当您单击 更改主题 按钮时 元素将添加一个类 da
  • 并行使用两个迭代器

    假设我有两个迭代器 并且我想计算 fancyoperation1 iter1 fancyoperation2 iter2 通常 我会简单地使用fancyoperation1 iter1 fancyoperation2 iter2 但是 如果
  • malloc(及其表兄弟)返回的内存块是否初始化为零?

    我写了一个代码来测试对Linux和Windows操作系统的内存管理进行压力测试 为了进一步测试 我继续检查 malloc 返回的内存中存在哪些值 返回的值均为 0 零 我已经阅读了 malloc 的手册页 在 Windows 和 Linux
  • 统一洗牌两个 numpy 数组的更好方法

    我有两个不同形状的 numpy 数组 但长度相同 主维 我想对它们中的每一个进行洗牌 以便相应的元素继续对应 即根据它们的前导索引一致地对它们进行洗牌 这段代码有效 并说明了我的目标 def shuffle in unison a b as
  • 从 A 到 Some(a) 的隐式转换

    出于好奇 我想知道是否可以做类似的事情 def myMethod a Option A None b Option B None z Option Z None Something 我想要的是不必这样称呼它 myMethod b Some
  • 如何使用 .htaccess 从 url 中删除扩展名而不使用尾部斜杠?

    我有一个 htaccess 文件 RewriteEngine On RewriteCond REQUEST FILENAME f RewriteRule 1 php NC L 我有一个名为random php 我只想打电话something
  • 计算多个值的不同行数

    让我们考虑一下这张表 它指定了一个人购买房产的次数 user property john car john car john house peter car peter car amanda house amanda house 我需要知道
  • 在 Mockito 中检测到未完成的存根

    我在运行测试时遇到以下异常 我正在使用 Mockito 进行嘲笑 Mockito 库提到的提示没有帮助 org mockito exceptions misusing UnfinishedStubbingException Unfinish