2012-08-13 55 views
33

我正在寻找一种方法来验证Mockito,在测试过程中没有任何与给定模拟的交互。对于具有验证模式never()的给定方法很容易实现,但是我还没有找到完整模拟的解决方案。Mockito - 如何验证模拟从未被调用

我实际上想达到的目标:在测试中验证,没有任何东西会打印到控制台。使用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();

回答

37

使用此:

解决这个问题的
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); 
} 
+0

看起来像我可以做的最好的方法。谢谢! (我实际上把大部分逻辑都隐藏在助手类中,并且不得不让沉默记录器) – 2012-08-13 15:51:58

6
verifyZeroInteractions(systemOut); 

正如在评论中指出的,这不适用于间谍。

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

+0

(facepalm) - 但它似乎没有与间谍工作,我必须嘲笑一个PrintStream,而不是设置它在系统上... – 2012-08-13 14:35:41

+0

没有看到你的代码,我猜测为什么这会失败的原因间谍是,当你存留间谍时,存根中的方法调用实际上算作一个被验证的方法。三点建议。 (1)'verifyNoMoreInvocations(ignoreStubs(mockOne,mockTwo));' - 这将像'verifyZeroInteractions'一样工作,但是忽略你已经存在的东西。 (2)您是否使用'doReturn/doThrow/doAnswer'方法来设置存根?当处理间谍时,这些通常比'当......',然后返回/ thenThrow/then'的效果更好。 ...继续 – 2012-08-13 21:29:31

+0

建议(3)是发布一些更多的代码,以便这里的人可以更好地帮助你。 – 2012-08-13 21:29:50

4

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

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

肯定是+1。不幸的是,我这次对Mockito的解决方案很感兴趣,所以我会接受另一个答案。希望你不介意:) – 2012-08-13 15:50:17

2

一种方法是重构你正在测试的类,允许可用于输出的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的影响。

+0

啊,好的,但不是我想要做的:我试图找到一种方法来测试一个类而不触摸它,特别是不添加仅用于测试的代码。但另一方面,如果我们愿意准备被测试的课程,那么这真是一个很好的方法! – 2012-08-14 12:43:37

相关问题