2012-09-16 39 views
0

我有一个非常简单的方法,我试图单元测试:的JUnit /的Mockito试验失败的离奇原因

public class MyAntTask extends org.apache.tools.ant.Task { 
    public void execute() { 
     fire(); 
    } 

    public void fire() { 
     // Do stuff 
    } 
} 

我只想写一个单元测试,确认调用​​总是调用fire(),所以我写了这个:

@Test 
public void executeCallsFire() { 
    //GIVEN 
    MyAntTask myTask = Mockito.mock(MyAntTask.class); 

    // Configure the mock to throw an exception if the fire() method 
    // is called. 
    Mockito.doThrow(new RuntimeException("fired")).when(myTask).fire(); 

    // WHEN 
    try { 
     // Execute the execute() method. 
     myTask.execute(); 

     // We should never get here; HOWEVER this is the fail() that's 
     // being executed by JUnit and causing the test to fail. 
     Assert.fail(); 
    } 
    catch(Exception exc) { 
     // THEN 
     // The fire() method should have been called. 
     if(!exc.getMessage().equals("fired")) 
      Assert.fail(); 
    } 
} 

我想(我决不是一个专家)通常的Mockito不能返回void,但是这是一个解决办法模拟的方法。你基本上说“用一个Mock包装我的对象,每当一个特定的方法即将被执行时,它总会返回一个特定的RuntimeException”。因此,Mockito不是实际执行fire(),而是看到它即将执行并引发异常。执行已验证?检查。

而不是通过,它在第一个Assert.fail()失败,正好在myTask.execute()的呼叫之下。

对于我的生活,我无法弄清楚为什么。下面是巨大的堆栈跟踪的JUnit的第一个10或-所以线是给我的失败:

java.lang.AssertionError 
    at org.junit.Assert.fail(Assert.java:92) 
    at org.junit.Assert.fail(Assert.java:100) 
    at net.myproj.ant.tasks.MyAntTaskUnitTest.executeCallsFire(MyAntTaskUnitTest.java:32) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:616) 

任何这里的想法,你们StackOverflow的的大师的Mockito?提前致谢!

+0

虽然fgb的答案是完全正确的,但我想知道你为什么要单元测试一行长,没有逻辑的方法。有一点,单元测试不再是你的时间经济用途。我从来没有找到一个很好的理由来编写一个像这个一样简单的方法的单元测试。 –

回答

6

由于myTask是一个模拟,真正的对象根本不会被调用。要调用一个真实的物体,请使用间谍。

您可以测试使用验证调用方法,因此不需要例外。

public void executeCallsFire() { 
    MyAntTask myTask = Mockito.spy(new MyAntTask()); 

    myTask.execute(); 

    Mockito.verify(myTask).fire(); 
} 

想嘲笑你正在测试的对象似乎不正确。设计测试通常会更好,以便验证对单独对象的调用。

+0

Mockito团队不赞同加上间谍作为部分嘲讽。 – Brice

0

我在这里看到更多的设计问题:

  1. 为什么你需要一个线方法和他们两个都公开?
  2. 这些模拟是用来模拟依赖关系,而不是用于测试的类
  3. 如果你会使私人火灾(名字不太清楚)。你不应该测试你的类的私人行为