Mockito中@Mock返回值未生效,测试时集合x始终为空的问题
问题原因与解决方案
核心问题
你测试里的B被Mock了,when(b.methodB(x)).thenReturn(1)是直接硬编码返回值,完全跳过了B的真实方法逻辑——B里调用A.method1修改集合x的代码根本没执行,再加上你原来的x只是声明没初始化(是null),自然集合一直是空的。
分场景解决
场景1:仅测试C类的逻辑(不关心B内部)
如果你的测试目标只是验证C正确调用了B的methodB,不需要B的真实逻辑,那可以用Answer模拟B修改集合的行为:
public class CTest { // 必须初始化集合,否则会报空指针 List<Map<Integer, List<String>>> x = new ArrayList<>(); @InjectMocks C c; @Mock B b; @Test public void test() { // 用Answer模拟B的行为:调用时修改传入的集合,再返回size when(b.methodB(anyList())).thenAnswer(invocation -> { List<Map<Integer, List<String>>> input = invocation.getArgument(0); // 往集合里加测试数据 Map<Integer, List<String>> testMap = new HashMap<>(); testMap.put(1, Arrays.asList("test-value")); input.add(testMap); return input.size(); }); c.methodC(x); // 此时x的size应该是1 assert x.size() == 1; } }
场景2:需要执行B的真实逻辑(同时Mock A)
如果要验证B的真实代码,那不能Mock整个B,要用@Spy保留B的真实逻辑,同时Mock它的依赖A:
public class CTest { List<Map<Integer, List<String>>> x = new ArrayList<>(); @InjectMocks C c; @Spy // 用Spy而不是Mock,保留B的真实方法 B b; @Mock // Mock B的依赖A A a; @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); // 把Mock的A注入到Spy的B中 b.a = a; } @Test public void test() { // 模拟A的method1修改集合的行为 doAnswer(invocation -> { List<Map<Integer, List<String>>> input = invocation.getArgument(0); Map<Integer, List<String>> testMap = new HashMap<>(); testMap.put(2, Arrays.asList("real-test-data")); input.add(testMap); return null; }).when(a).method1(anyList()); c.methodC(x); // 此时x会被A的模拟逻辑修改,size为1 assert x.size() == 1; } }
额外注意点
- 必须初始化集合
x:你原来的代码里x只是声明,没有实例化,会导致空指针异常,一定要写成new ArrayList<>()。 - 如果不需要Mock A,想让A的真实逻辑执行,那可以去掉对A的Mock,直接让Spy的B使用真实的A实例。
内容的提问来源于stack exchange,提问作者Bara' Al-jawarnEh
相关产品推荐
相关产品推荐

