【问题标题】:Java Easymock complains with "java.lang.IllegalStateException: void method cannot return a value" or "no last call on a mock available"Java Easymock 抱怨“java.lang.IllegalStateException:void 方法无法返回值”或“没有可用的模拟的最后调用”
【发布时间】:2012-04-10 17:00:39
【问题描述】:

我们正在使用 EasyMock 对 Eclipse 中的 Java 应用程序进行 JUnit 测试。使用与下面类似的代码,我们发现了一个奇怪的行为:当运行完整的测试套件(Eclipse 项目 -> 运行方式 -> 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)

有一个similar question here,但是好像不相关。

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

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

我在 Google 和 StackOverflow 上都没有找到答案,但我现在发现了自己,所以本着answering your own questions 的精神,我将在下面发布我的发现。值得一提的是我发现的这篇文章,尽管它在这种特殊情况下对我没有帮助:EasyMock Cause-Effect Exception Mapping

【问题讨论】:

  • 我将您的代码复制到 Eclipse 中的一个测试项目中,套件和测试都运行良好。不确定如何重现您的错误?使用静态代码块而不是 @BeforeClass 对我来说似乎是一种代码味道。
  • 我刚刚尝试使用新下载的 Eclipse (Indigo Service Release 2)、JUnit (4.10) 和 EasyMock (3.1) 以及在项目上运行所有测试时(包资源管理器,右键单击项目,运行作为,JUnit 测试),它将运行 testGravity 两次,第二次失败。
  • 我同意我正在稍微改变行为。我不确定它是否已经是代码异味——也许静态的最终初始化声明是要更改的部分,而不是模拟设置变成静态的。如果您找到更好的解决方案,我很想知道:)

标签: java junit easymock illegalstateexception


【解决方案1】:

在初始化 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 并在第二次运行时失败。该修复也适用于两者。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多