Mockito - 如何验证模拟是否从未被调用



我正在寻找一种方法来验证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();

使用这个:

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);
}
verifyZeroInteractions(systemOut);

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

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

由于原始正确答案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);
    }
}

你可以尝试一个稍微不同的策略:

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);
}

如果您愿意,您可以将匿名类型切换为模拟并按照 Don Roby 的建议进行验证。

解决此问题的一种方法是重构您正在测试的类,以允许注入可用于输出的 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的影响。

最新更新