0

我有一个非常简单的方法,我正在尝试进行单元测试:

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

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

我只想写一个单元测试来确认调用execute()总是调用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因此,fire()Mockito 并没有实际执行,而是看到它即将执行并抛出异常。执行验证?查看。

它没有通过,而是在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 大师们,这里有什么想法吗?提前致谢!

4

2 回答 2

6

因为 myTask 是一个模拟对象,所以根本不会调用真正的对象。要调用真实对象,请使用间谍。

您可以使用 verify 测试是否调用了方法,因此不需要异常。

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

    myTask.execute();

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

想要模拟您正在测试的对象似乎并不正确。通常最好设计测试,以便您验证对单独对象的调用。

于 2012-09-16T02:10:17.387 回答
0

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

  1. 为什么你需要一个 line 方法并且它们都是 public 的?
  2. 模拟用于模拟依赖关系,而不是用于测试中的类
  3. 如果您将火灾(名称不清楚)设为私有。你不应该测试你班级的私人行为
于 2012-09-16T09:31:49.343 回答