Java Easymock抱怨“java.lang.IllegalStateException:void方法无法返回值”或“没有最后一次调用可用的模拟”

问题描述 投票:2回答:1

我们正在使用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)

有一个similar question here,但它似乎是无关的。

在我们真正的测试代码中(更大的类,但主要的actor与精简的示例相同)这个例外:

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

java junit easymock illegalstateexception
1个回答
0
投票

将断点放在初始化APPLE和SetUpClass()内部的行上我注意到APPLE只被调用一次,而SetUpClass被调用两次。这是因为对牛顿的第一次引用创建了类并运行了静态初始化器,但是JUnit为每次测试运行调用了@BeforeClass。在这种情况下,测试运行两次:一次作为普通呼叫,一次作为测试套件的一部分。

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

public class Newton {

    [...]

    static {
        expect(APPLE.fall()).andReturn("Targeting HEAD").anyTimes();
        replay(APPLE);
    }

    // no @BeforeClass needed anymore

    [...]
}

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

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

© www.soinside.com 2019 - 2024. All rights reserved.