EasyMock的一个大坑

本文分析了使用EasyMock框架进行单元测试时遇到的常见错误java.lang.IllegalStateException:Nmatchersexpected,Mrecorded,并给出了问题产生的原因及解决方案。推荐采用新一代测试框架Mockito以避免类似问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题

项目里大量单元测试采用了EasyMock框架,Maven命令跑测试总是报如下错误:

java.lang.IllegalStateException: N matchers expected, M recorded.

打开报错的单元测试,无论是通过命令: mvn test -Dtest=Mytest,还是通过eclipse单独运行,均无法重现问题。

record-replay-verify模型

EasyMock基于: record-replay-verify 模型
EasyMock分三个阶段:

  • Record

    创建mock对象,并定义mock对象的行为。

  • Replay

    在replay阶段,执行被测试的方法。项目组的新人总是忘写replay方法。

  • Verify
    验证mock对象的返回结果

问题分析

问题就出在verify方法上。
查阅资料发现,若测试中抛出一个异常,当前单元测试中的verify方法没有进入,那么EasyMock就继续Record下一个单元测试,并最终在其他单元测试上报错。

查阅到的英文原文如下:

because we throw an exception from a mock object and catch it via JUnit‘s “expected” annotation.
Code never comes to verify() and EasyMock never closes recording state of mock. 
EasyMock continues to record states of other tests and this test will cause the other tests to fail.

问题代码示例

@Test (expected = RuntimeException.class) 
public void testExperiment() {
        Filter filter = createMock(Filter.class);
        // 1. Record阶段,记录mock对象上的操作
        EasyMock.expect(filter.getById("1001")).andReturn(expectedUser);
        // 模拟抛出一个异常
        expectLastCall().andThrow(new RuntimeException("test"));
        // 2. Replay阶段,这一步才是真正的执行被测试的方法。
        replay(filter);
        // 3. verify阶段,由于前面产生了异常verify根本就没有进入
        verify(filter);
    }

解决方法

其中一个方法是所有的单元使用EasyMockSupport创建,然后在@After方法里面调用 resetAll(),重置mock对象,避免污染下一个测试方法。

    @After
    public void reSetMock() {
        easyMockSupport.resetAll();
    }

但由于EasyMock使用复杂,定位问题较难。
有些问题能找到原因,有些问题找不到原因,有解决方法即可:全面改用新一代测试框架Mockito。Mockito隐式使用了record-replay-verify,避免了忘写replay造成的问题,避免了被其他测试搞坏。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值