【问题标题】:Mockito - how to verify that a mock was never invokedMockito - 如何验证从未调用过模拟
【发布时间】:2012-08-09 19:12:23
【问题描述】:

我正在寻找一种使用 Mockito 验证的方法,即在测试期间与给定的模拟没有任何交互。对于具有验证模式never() 的给定方法,很容易实现这一点,但我还没有找到完整模拟的解决方案。

我真正想要实现的目标:在测试中验证,没有任何东西打印到控制台。 jUnit 的总体思路是这样的:

private PrintStream systemOut;

@Before
public void setUp() {
    // spy on System.out
    systemOut = spy(System.out);
}

@After
public void tearDown() {
    verify(systemOut, never());  // <-- that doesn't work, just shows the intention
}

PrintStream 有很多方法,我真的不想用单独的验证来验证每一个方法——System.err 也是如此......

所以我希望,如果有一个简单的解决方案,我可以,考虑到我有很好的测试覆盖率,强制软件工程师(和我自己)删除他们的(我的)调试代码,比如 System.out.println("Breakpoint#1");e.printStacktrace();在提交更改之前。

【问题讨论】:

    标签: java junit mockito


    【解决方案1】:
    verifyZeroInteractions(systemOut);
    

    如 cmets 中所述,这不适用于间谍。

    对于大致等效但更完整的答案,请参阅 gontard 对此问题的回答。

    【讨论】:

    • (facepalm) - 但它似乎不适用于间谍活动,我必须模拟一个 PrintStream 并将其设置在 System...
    • 没有看到你的代码,我猜你的间谍失败的原因是当你存根你的间谍时,存根中的方法调用实际上算作一个要验证的。三个建议。 (1) verifyNoMoreInvocations(ignoreStubs(mockOne, mockTwo)); - 这将像 verifyZeroInteractions 一样工作,但忽略你已经存根的内容。 (2) 您是否使用doReturn/doThrow/doAnswer 方法来设置您的存根?在处理间谍方面,这些通常比when...thenReturn/thenThrow/then 更有效。 ...继续
    • 建议(3)是多贴一些你的代码,让这里的人能更好的帮助你。
    • @David,我的代码示例已经完成。没有更多的相关行。但我期待着一个与 mockito 间谍一起工作的解决方案。如果我可以只监视System.out 而不是暂时用模拟替换流,那将更加优雅。
    • 好的,谢谢,我现在更了解您的需求了。我确实有一个不同于 gontard 和 McDowell 的解决方案 - 我现在没有时间发布它,但我会在几个小时内完成。
    【解决方案2】:

    您可以尝试稍微不同的方法:

    private PrintStream stdout;
    
    @Before public void before() {
        stdout = System.out;
        OutputStream out = new OutputStream() {
            @Override public void write(int arg0) throws IOException {
                throw new RuntimeException("Not allowed");
            }
        };
        System.setOut(new PrintStream(out));
    }
    
    @After public void after() {
        System.setOut(stdout);
    }
    

    如果您愿意,可以将匿名类型切换为模拟并验证as Don Roby suggests

    【讨论】:

    • 绝对是+1。不幸的是,这次我对 Mockito 的解决方案很感兴趣,因此我会接受另一个答案。希望你不介意:)
    【解决方案3】:

    使用这个:

    import static org.mockito.Mockito.verifyZeroInteractions;
    
    // ...
    
    private PrintStream backup = System.out;
    
    @Before
    public void setUp() {
        System.setOut(mock(PrintStream.class));
    }
    
    @After
    public void tearDown() {
        verifyZeroInteractions(System.out);
        System.setOut(backup);
    }
    

    【讨论】:

    • 看起来我可以为这种方法做的最好的。谢谢! (实际上,我已经将大部分逻辑隐藏在辅助类中,并且也不得不让 Logger 静音;))
    • verifyZeroInteractions 现已弃用,取而代之的是 org.mockito.Mockito#verifyNoInteractions
    【解决方案4】:

    解决此问题的一种方法是重构您正在测试的类,以允许注入可用于输出的 PrintStream。这将允许您对其进行单元测试,而无需依赖 System 类的行为。您可以为此注入使用包私有构造函数,因为您只会在相应的测试类中使用它。所以它可能看起来像这样。

    public class MyClass{
        private PrintWriter systemOut;
    
        public MyClass(){
            this(System.out);
        }
    
        MyClass(PrintWriter systemOut){
            this.systemOut = systemOut;
    
            // ...any other initialisation processing that you need to do
        }
    }
    

    在类本身中,使用 systemOut 变量而不是 System.out,无论您调用后者。

    现在,在测试类中,创建一个模拟 PrintStream,并将其传递给包私有构造函数,以获取您要测试的对象。现在您可以从测试中运行您喜欢的任何操作,并使用 verify 检查它们对您的模拟 PrintStream 的影响。

    【讨论】:

    • 啊,好吧,但不完全是我打算做的:我试图找到一种方法来测试一个类而不接触它,特别是不添加仅用于测试的代码。但另一方面,如果我们愿意准备被测类,那么这确实是一个不错的方法!
    【解决方案5】:

    由于原来的正确答案,verifyZeroInteractions 已被弃用,请改用verifyNoInteractions

    import org.junit.jupiter.api.Test;
    
    import static org.mockito.Mockito.*;
    
    public class SOExample {
    
        @Test
        public void test() {
            Object mock = mock(Object.class);
            verifyNoInteractions(mock);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-01
      • 2013-10-18
      • 1970-01-01
      • 1970-01-01
      • 2018-11-03
      • 2014-07-14
      • 2014-04-01
      相关资源
      最近更新 更多