EasyMock添加mock方法后仍执行原实现,Java单元测试mock构造函数问题
嘿,我之前也踩过EasyMock这个坑!你遇到的问题——用addMockedMethod指定了要mock的方法,但原实现还是跑起来了,大概率是这几个原因导致的,咱们一步步捋清楚解决办法:
1. 先检查被mock方法的修饰符
EasyMock是基于JDK动态代理实现的,final、static、private方法是没法被代理覆盖的,所以如果你要mock的isProxied或者另一个方法是这些修饰符,那必然会执行原逻辑。
解决办法:
- 如果能改源码,把方法改成非final、非static的public/protected方法
- 要是没法改源码,就得配合PowerMock一起用,它能搞定final/static方法的mock
2. 确认MockBuilder的用法是否符合你的需求
EasyMock的MockBuilder有两种常见用法,别搞混了:
情况A:你想让所有方法都被mock(未录制的方法返回默认值)
这种情况根本不需要用addMockedMethod,直接构建完整mock就行:
CallToBeMocked mockCallToBeMocked = EasyMock.createMockBuilder(CallToBeMocked.class) .withConstructor(ArgumentA.class, ArgumentB.class, ArgumentC.class) .withArgs(mockArgumentA, mockArgumentB, mockArgumentC) .createMock(); // 关键:最后一定要调用createMock()生成实例
这样所有方法都会被mock,调用时没录制预期的话,会返回对应类型的默认值(比如boolean返回false,对象返回null)。
情况B:你只需要mock指定的两个方法,其他方法执行原实现(部分mock)
这种情况才需要用addMockedMethod,但必须为被mock的方法录制预期行为,不然要么执行原方法,要么抛出异常:
// 构建部分mock,仅指定方法被mock CallToBeMocked mockCallToBeMocked = EasyMock.createMockBuilder(CallToBeMocked.class) .withConstructor(ArgumentA.class, ArgumentB.class, ArgumentC.class) .withArgs(mockArgumentA, mockArgumentB, mockArgumentC) .addMockedMethod("isProxied", ArgumentA.class) .addMockedMethod("yourSecondMethod", YourParamType.class) // 替换成你要mock的第二个方法 .createMock(); // 给mock方法录制预期行为 EasyMock.expect(mockCallToBeMocked.isProxied(mockArgumentA)).thenReturn(true); // 自定义返回值 EasyMock.expect(mockCallToBeMocked.yourSecondMethod(anyObject())).thenReturn(yourExpectedResult); // 切换到回放模式,这步不能忘! EasyMock.replay(mockCallToBeMocked);
3. 检查代码是否遗漏了关键步骤
从你的代码片段看,最后只写到.addMockedMethod("isProxied", ArgumentA.class) .a...,大概率没写完——一定要确保最后调用了createMock()来生成真正的mock实例,不然你拿到的不是mock对象,自然会执行原方法。
4. 试试升级EasyMock版本
有些旧版本的EasyMock在处理带构造函数的部分mock时存在bug,建议升级到最新的稳定版(比如4.x系列),说不定问题就直接消失了。
总结一下,最常见的问题就是方法是final/static,或者没录制预期行为,或者MockBuilder的用法不对。先排查方法修饰符,再检查mock构建和预期录制的步骤,应该就能解决啦!
内容的提问来源于stack exchange,提问作者Sonu Mishra

