如何在JUnit中Mock类内部依赖并捕获Void方法的调用参数
问题出得很典型——你测试里mock的ClassB对象,和A的method1内部自己new出来的ClassB完全是两个毫无关系的实例!Mockito根本监控不到后者的调用,自然会报mock未被调用的错误。
要解决这个问题,核心是让A使用你创建的mock实例,而不是自己去new。最合理的方式是通过依赖注入重构原代码,然后在测试中把mock对象注入进去。下面是具体的修改步骤:
1. 重构原类A,支持依赖注入
把ClassB的实例通过构造函数传入A,而不是在方法内部new:
class A{ private final ClassB b; // 构造注入ClassB依赖 public A(ClassB b) { this.b = b; } public void method1(String name){ // 不再创建新的ClassB实例,使用注入的对象 // 这里的argument1是你业务逻辑里的参数,保持不变 b.method2(argument1); } }
(注意:Java类名规范是首字母大写,建议把classB改成ClassB,避免混淆)
2. 修改测试类,让Mock生效
在测试中,我们用Mockito的@Mock创建ClassB的mock实例,再通过@InjectMocks自动注入到A的实例中,同时别忘了给测试方法加@Test注解:
import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.times; class ATest{ private String name = "name"; @Mock private ClassB mockB; @InjectMocks private A a; @Before public void setup(){ // 初始化Mockito的注解 MockitoAnnotations.openMocks(this); // 如果你不想用@InjectMocks,也可以手动创建A实例: // a = new A(mockB); } @Test public void testMethod1() { // 调用被测方法 a.method1(name); // 创建参数捕获器 ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); // 验证mockB的method2被调用1次,并捕获传入的参数 verify(mockB, times(1)).method2(captor.capture()); // 获取捕获的参数并做断言 String actual = captor.getValue(); assertEquals("some data", actual); } }
额外注意事项
- 测试方法必须标注
@Test注解,否则JUnit不会执行这个测试用例 - 如果因为某些原因不能修改原类的构造函数,也可以用PowerMockito来mock
new ClassB()这个动作,但这种方式属于侵入式测试,不推荐,最好还是通过依赖注入解耦代码,让测试更优雅。
内容的提问来源于stack exchange,提问作者Chandan Kumar Barik
相关产品推荐
相关产品推荐

