Spring Data JPA与Mockito:测试中save()返回null的原因及免Mock疑问
问题解答
为什么断言失败,save方法返回null?
Mockito创建的Mock对象,所有未显式指定行为的方法,默认会返回对应类型的"默认值":引用类型返回null,基本类型返回0/false等。你只Mock了findByUsername方法的行为,没有指定save方法的返回值,所以调用accountRepository.save(account)时,Mock对象会返回null,Service把这个null返回后,和你创建的new Account("floatfoo", "Egor")做相等比较,自然断言失败。
能不能不Mock save方法?
直接用普通Mock对象的话不行——因为默认返回null会导致Service返回null,断言还是会失败。但可以通过两种方式避免显式指定save的具体返回值:
- 使用Mockito的Answer让save返回传入的参数:不用硬编码Account的属性,让Mock的save方法直接返回你传入的对象,这样Service返回的就是你创建的那个Account,断言就能通过。示例代码:
@Test void createAccount_Should_Return_Account() throws InstanceAlreadyExistsException { AccountRepository ar = mock(AccountRepository.class); when(ar.findByUsername("floatfoo")).thenReturn(Optional.empty()); // 让save返回传入的参数 when(ar.save(any(Account.class))).thenAnswer(invocation -> invocation.getArgument(0)); AccountService as = new AccountService(ar); assertEquals(new Account("floatfoo", "Egor"), as.createAccount("floatfoo", "Egor")); }
- 使用Spy对象(如果你的AccountRepository是接口或可继承类):Spy会优先调用真实方法,只有显式Mock的方法才会被替换。但要注意,如果真实的save方法依赖数据库等外部资源,Spy可能会引发实际的数据库操作,这在单元测试中通常是不推荐的,所以还是用第一种方法更稳妥。
另外,你也可以给Mock对象设置全局默认行为,比如mock(AccountRepository.class, Mockito.RETURNS_SMART_NULLS),但这会影响所有未Mock的方法,不如针对性处理save方法清晰。
内容的提问来源于stack exchange,提问作者floatfoo
相关产品推荐
相关产品推荐

