使用Mockito4.* 模拟单例时的用例交互

72qzrwbm  于 2022-12-13  发布在  其他
关注(0)|答案(3)|浏览(210)

我写了一个名为DemoSingleTon的singleTone,一个名为DemoMain的主类和一个名为DemoTest的测试类,当单独测试DemoTest的所有测试时,测试都能成功运行,如果所有测试一起运行,后两个用例总是会失败,看起来后面的mockStatic没有起作用。

第一个
建立以下等级:

testImplementation group: 'org.mockito', name: 'mockito-inline', version: '4.9.0'
testImplementation('org.junit.jupiter:junit-jupiter-api:5.6.2')
testImplementation('org.junit.jupiter:junit-jupiter-engine:5.6.2')

我认为对mockitoStatic的每个调用都应该是独立的,而不应该相互交互。

gwbalxhn

gwbalxhn1#

public class DemoMain {
    private static final DemoSingleTon instance = DemoSingleTon.getInstance();
}

只在第一次加载类时执行一次DemoSingleton.getInstance(),并将引用赋给instance字段。一旦发生这种情况,您的静态模拟就不能再拦截方法调用,因为该方法再也不会被调用。加载类发生在第一次访问类时,即:

try (MockedStatic<DemoSingleTon> mockedStatic = Mockito.mockStatic(DemoSingleTon.class)) {
            DemoSingleTon testUtil1 = Mockito.mock(DemoSingleTon.class);
            mockedStatic.when(DemoSingleTon::getInstance).thenReturn(testUtil1);
            Mockito.when(testUtil1.test("input1")).thenReturn("nothing");

            DemoMain demoMain = new DemoMain(); // <-- class loaded here and DemoSingleton.getInstance is called (which is intercepted by your mock)

            assertEquals("nothing", demoMain.testInputUseSingleTone());
        }

如果将主类实现更改为以下内容,则行为会有所不同:

public class DemoMain {
    public String testInputUseSingleTone() {
        return DemoSingleTon.getInstance().test("input1");
    }
}

因为现在,每次调用方法时都会调用DemoSingleton.getInstance(),因此可以被静态模拟拦截。
从本质上讲,这个问题是Why is my class not calling my mocked methods in unit test?的另一个变体,尽管有点棘手。帮你自己一个忙,退一步想想如何使你的设计更可测试,而不需要静态模拟。

roejwanj

roejwanj2#

你自己对斯波克的回答不起作用,有几个原因:
1.测试使用new DemoMain(demoSingleTon : demoTon),但该名称的字段不存在。现有的构造函数应为new DemoMain()
1.修复此问题后,test1()test2()都将失败,并出现类似Condition not satisfied: "nothing" == demo.testInputUseSingleTone()的错误。
1.您正在尝试模拟类DemoSingleTon,但由于无法模拟final类,因此无法工作。
1.但是像这样在(3)中模拟单例不会有任何效果,因为由于(1),你没有正确地将它注入DemoMain
1.您将DemoSingleTon.instance设置为非final,但随后您没有使用该选项在那里注入mock示例。
还有更多,但这些都是我马上注意到的。如果你在这里发布一个答案,确保它不是未经测试的伪代码。否则,当你要求我改进它时,我怎么能为你改进它呢?你声称你的解决方案有效,但显然这是不可能的。我甚至尝试了,以确认它。
我也不明白为什么你要把DemoSingleTon.getInstance()的结果存储在另一个静态变量中。所有这些过早的优化使你的代码更难测试。你想在内存消耗和性能等方面努力是很好的,但是你真的有问题吗?也许首先你应该让被测试的代码正常工作,然后再进行测试。
像这样的怎么样?
第一个
这样就更有意义了,而且测试实际上会通过:

63lcw9qa

63lcw9qa3#

非常感谢@kriegaex的建议。我尝试修改演示并使用spock来测试它。当将示例更改为非最终版本时,它工作得很好。
第一个
斯波克测试代码如下:

class DemoTest extends Specification {

    def "test"() {
        given:
        def demo = new DemoMain()

        expect:
        "input1" == demo.testInputUseSingleTone()
    }

    def "test1"() {
        given:
        def demoTon = Mock(DemoSingleTon.class)
        demoTon.test(_) >> "nothing"
        def demo = new DemoMain(demoSingleTon: demoTon)

        expect:
        "nothing" == demo.testInputUseSingleTone()
    }

    def "test2"() {
        given:
        def demoTon = Mock(DemoSingleTon.class)
        demoTon.test(_) >> "everything"
        def demo = new DemoMain(demoSingleTon: demoTon)

        expect:
        "everything" == demo.testInputUseSingleTone()
    }
}

相关问题