在套件测试期间,EasyMock 说 0 个匹配器预期 1 个记录

Posted

技术标签:

【中文标题】在套件测试期间,EasyMock 说 0 个匹配器预期 1 个记录【英文标题】:During suite tests EasyMock says 0 matchers expected 1 recorded 【发布时间】:2011-01-18 14:40:51 【问题描述】:

所以我使用 EasyMock 的类扩展已经有一段时间了。突然间我得到了这个异常,但只有当我运行整个测试套件时:

java.lang.IllegalStateException: 0 matchers expected, 1 recorded.
at org.easymock.internal.ExpectedInvocation.createMissingMatchers(ExpectedInvocation.java:42)
at org.easymock.internal.ExpectedInvocation.<init>(ExpectedInvocation.java:34)
at org.easymock.internal.ExpectedInvocation.<init>(ExpectedInvocation.java:26)
at org.easymock.internal.RecordState.invoke(RecordState.java:64)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:24)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:56)
at org.easymock.classextension.internal.ClassProxyFactory$1.intercept(ClassProxyFactory.java:74)
at com.protrade.soccersim.data.emulator.matrix.PositionCategoryMatrix$$EnhancerByCGLIB$$c5298a7.getPossession(<generated>)
at com.protrade.soccersim.data.emulator.stats.team.PossessionCalculatorUnitTest.testDeterminePossessionHomeWin(PossessionCalculatorUnitTest.java:45)

涉及的代码就是这个小美人(修剪了一下):

    @Before
public void setUp() throws Exception 
    homeTeam = createMock( PositionCategoryMatrix.class );
    awayTeam = createMock( PositionCategoryMatrix.class );
    ...


@Test
public void testDeterminePossessionHomeWin() 
    expect(homeTeam.getPossession()).andReturn( 0.15151515 );
    expect(awayTeam.getPossession()).andReturn( 0.01515152 );
    replay( homeTeam, awayTeam );
    ...

在第一次期望时抛出异常。这真的没有意义。它说它正在获得一个匹配器,但该方法甚至不带参数。奇怪的是,它只是在测试套件期间!我在@Before 中创建了一个新的模拟,所以它不应该从其他地方继承任何东西(不是其他方法会有匹配器)

那么,有什么想法吗?

【问题讨论】:

我也得到了这个(这与错误消息上所有其他类似的谷歌结果之间的主要区别是记录的数字比预期的数字大......这表明它不是由常量/匹配器混合引起的“缺少匹配器”。)这是关于 EasyMock 可能最简单的使用 - 我以前怎么从来没有遇到过这种情况? (我在 2.5.2 和 3.0 都试过了,结果差不多。) 【参考方案1】:

我厌倦了在必须使用 EasyMock 的每个新旧代码库中看到这种情况。写一个新的 EasyMock 测试,突然随机测试开始失败,因为 Matchers 从未被捕获。所以我去看看 EasyMock 是如何存储这些 Matchers 的。它使用了最后一个类 LastControl,在该类中有几个线程本地,用于存储不同的东西。其中之一是给 Matchers 的。幸运的是,那里有一个静态方法可以从仍然存在的线程本地中提取所有匹配器。所以这给了我这个想法(在同事的帮助下,感谢 Sven,他想要功劳)

/**
 * Base class to make sure all EasyMock matchers are cleaned up.  This is not pretty but it will work
 * 
 * @author N069261KDS
 *
 */
public class BaseTest 

  @Before
  public void before()
    LastControl.pullMatchers();
  

  @After
  public void after()
    LastControl.pullMatchers();
  


基本上,让您因 Matchers 错误而失败的测试从此类扩展,您将确保 Matchers 已被清除。请注意,这是一种解决方法。有问题的测试应该一开始就写好。但是,如果您必须通过 5000 多个测试,这是两害相权取其轻。我希望这会对人们有所帮助!

【讨论】:

【参考方案2】:

虽然这确实可能是由“愚蠢的”EasyMock 错误导致的虚假消息,但也很可能是由于对 EasyMock API 的无效使用。在我的情况下,消息来自这个 JUnit 3.8 测试(和你一样,这只发生在我运行我的整个测试套件时,并且只通过 Maven,而不是 Eclipse):

public void testSomething() 
    // Set up
    MyArgumentType mockArg = (MyArgumentType) EasyMock.anyObject(); // bad API usage

    // Invoke the method under test
    final String result = objectUnderTest.doSomething(mockArg);

    // Verify (assertions, etc.)
    ...

我应该使用 createMock(MyArgumentType.class) 或其变体之一,而不是使用 anyObject()。我不知道我在想什么,我已经编写了数百万个这样的测试并正确使用了 API。

令人困惑的一点是,由于“匹配器数量错误”消息而失败的测试不一定(或曾经?)您错误地使用了 API。这可能是在包含 replay() 或 verify() 方法的错误测试之后执行的第一个测试,但我还没有通过实验验证这一点。

【讨论】:

这正是发生在我们身上的事情。有人在EasyMock.expect(...) 方法之外使用了匹配器,并毒化了 EasyMock 状态 有趣。请注意,我认为整个 Java 世界已经转向 Mockito(需要引用),更加类型安全。 我被告知了很多,但目前我们已经用 EasyMock 编写了超过 1.5k 的测试,所以我们不太可能很快切换【参考方案3】:

我收到了同样的错误信息。我(不小心)在对被测类的调用中使用了 isA() 声明

classUnderTest.callStateChanged(calls, isA(LoggingOnlyListener.class));

我的意思是:

classUnderTest.callStateChanged(calls, new LoggingOnlyListener());

而且每次都失败了。

【讨论】:

【参考方案4】:

我刚刚遇到了这个问题,我想我设法解决了。对我来说,这是由于之前的测试(在不同的类中),我(错误地)在 Assert.assertEquals 方法中使用了 EasyMock 匹配器。

在调用第一个期望方法之前,EasyMock 似乎无法抱怨报告的额外匹配器。

【讨论】:

【参考方案5】:

我遇到了类似的问题。根据我的观察,甚至方法返回都使用 Matchers 进行匹配。因此,如果您的第一个方法因任何原因失败,则返回匹配的匹配器仍在堆栈中。这可能是您看到记录 1 个匹配器的原因之一,即使您的方法不带任何参数。基本上,第一个方法调用从未返回值。

【讨论】:

【参考方案6】:

您使用的是哪个版本的 Easymock? 我阅读了关于 v.2.5.2 发布的post,以前的版本可能有一个

捕获中的愚蠢错误

尝试使用 Easymock 2.5.2+

【讨论】:

以上是关于在套件测试期间,EasyMock 说 0 个匹配器预期 1 个记录的主要内容,如果未能解决你的问题,请参考以下文章

EasyMock失败的测试用例“无效使用参数匹配器! 2匹配预期,1记录“错误

测试没有使用 EasyMock 调用 void 方法

使用匹配“^((?!:ios:).)*$”的测试运行所有匹配 /e2e/i 的测试套件

如何使用Spring + EasyMock做Java单元测试

JUnit 测试通过但 PIT 说套件不是绿色的

EasyMock 作废方法