Java Easymock抱怨"java.lang.IllegalStateException: void method cannot return a value"或"no last call on



我们使用 EasyMock 在 Eclipse 中对我们的 Java 应用程序进行 JUnit 测试。使用类似于下面的代码,我们发现了一个奇怪的行为:当运行完整的测试套件(Eclipse Project -> Run As -> JUnit)时,一个测试用例可重现地失败。但是,当独立运行时,它可以正常工作。

接口:

package de.zefiro.java.easymockexception;
public interface Fruit {
    public String fall();
}

测试类:

package de.zefiro.java.easymockexception;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertTrue;
import org.junit.BeforeClass;
import org.junit.Test;
public class Newton {
    private static final Fruit APPLE = createNiceMock(Fruit.class);
    @BeforeClass
    public static void SetUpClass() {
        expect(APPLE.fall()).andReturn("Targeting HEAD").anyTimes();
        replay(APPLE);
    }
    @Test
    public void testGravity() {
        String target = APPLE.fall();
        assertTrue("Missed", target.contains("HEAD"));
    }
}

测试套件:

package de.zefiro.java.easymockexception;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(value = Suite.class)
@SuiteClasses( { Newton.class } )
public class ScienceTests { }

在 Eclipse 项目上运行所有测试 - 即 ScienceTests 调用 Newton 和直接调用 Newton - 在上面的小示例中产生了以下异常:

java.lang.IllegalStateException: no last call on a mock available
at org.easymock.Easymock.getControlForLastCall(EasyMock.java:175)

这里有一个类似的问题,但似乎无关。

在我们真正的测试代码中(更大的类,但主要参与者与精简的示例相同),此异常:

java.lang.IllegalStateException: void method cannot return a value
at org.easymock.internal.MocksControl.andReturn(MocksControl.java:101)

我在Google和StackOverflow上都没有找到答案,但现在找到了自己,所以本着回答你自己的问题的精神,我将在下面发布我的发现。值得一提的是我发现的这篇文章,尽管它在这种特殊情况下对我没有帮助: EasyMock 因果异常映射

将断点放在初始化 APPLE 的行上并在 SetUpClass() 中,我注意到 APPLE 只被调用一次,而 SetUpClass 被调用两次。这是因为对 Newton 的第一个引用会创建类并运行静态初始值设定项,但是 JUnit 为每次测试运行调用@BeforeClass。在这种情况下,测试运行两次:一次作为正常调用,一次作为测试套件的一部分。

我不想更改逻辑(即不使用静态),而是将静态@BeforeClass更改为静态初始化块:

public class Newton {
    [...]
    static {
        expect(APPLE.fall()).andReturn("Targeting HEAD").anyTimes();
        replay(APPLE);
    }
    // no @BeforeClass needed anymore
    [...]
}

这解决了我上面的简化测试和我们实际测试编码中的问题。

我没有找出触发不同异常消息的区别是什么,但结果是相同的 - new 只调用一次,@BeforeClass多次调用并在第二次运行时失败。该修复程序也适用于两者。

最新更新