为何调用Helper方法的JUnit测试未按预期抛出异常?
问题:JUnit测试未按预期抛出异常的原因分析
相关代码
Service类
public class AccountServiceImpl { @Autowired AccountHelper accountHelper; @Override public Account createAccount(Account account) throws CustomerNotFoundException { accountHelper.checkAccountTypeForCustomer(account); return accountRepository.save(account); } }
Helper类
public void checkAccountTypeForCustomer(Account acc) throws CustomerNotFoundException { Boolean customerExists = customerRepository.existsById(acc.getCustomerId()); if(!customerExists) { throw new CustomerNotFoundException("604", Message.CUSTOMER_NOT_FOUND); } }
测试类
@ExtendWith(MockitoExtension.class) public class AccountServiceTest { @Mock private AccountRepository accountRepository; @Mock private CustomerRepository customerRepository; @Mock private AccountHelper accountHelper; @InjectMocks private AccountService testService; @Test void testCreateAccount() throws CustomerNotFoundException { Account account = Account.builder() .accountType(AccountType.SAVINGS) .openingBalance(BigDecimal.valueOf(3000)) .ifsc("IFSC1") .customerId(1) .build(); testService.createAccount(account); } }
问题原因
你当前测试未抛出异常的核心问题是:你把AccountHelper声明成了@Mock对象。Mockito的Mock对象默认不会执行原类的真实方法逻辑,调用Mock对象的方法时只会做“空操作”——既不会执行检查客户是否存在的逻辑,也不会抛出异常,所以测试能顺利通过。
而当你把checkAccountTypeForCustomer()的逻辑移到Service方法内部时,这段逻辑属于Service的真实代码(没有被Mock),此时执行测试时会真实检查客户是否存在,自然会抛出异常导致测试失败,这符合预期。
修正方案
方案1:测试AccountHelper的真实逻辑
如果要验证AccountHelper的真实检查逻辑是否生效,不要把它声明为@Mock,改用@Spy(保留真实方法逻辑,同时可对其依赖的Mock对象进行配置):
@ExtendWith(MockitoExtension.class) public class AccountServiceTest { @Mock private AccountRepository accountRepository; @Mock private CustomerRepository customerRepository; @Spy // 改用@Spy,保留AccountHelper的真实逻辑 private AccountHelper accountHelper; @InjectMocks private AccountService testService; @Test void testCreateAccount_ThrowsCustomerNotFound() { Account account = Account.builder() .accountType(AccountType.SAVINGS) .openingBalance(BigDecimal.valueOf(3000)) .ifsc("IFSC1") .customerId(1) .build(); // 模拟客户不存在的场景 when(customerRepository.existsById(1)).thenReturn(false); // 断言调用createAccount时会抛出异常 assertThrows(CustomerNotFoundException.class, () -> testService.createAccount(account)); } }
方案2:验证Service对AccountHelper的调用逻辑
如果只是要验证Service层是否正确调用了AccountHelper的方法,同时模拟异常场景,可以保留@Mock的AccountHelper,手动指定其方法行为:
@ExtendWith(MockitoExtension.class) public class AccountServiceTest { @Mock private AccountRepository accountRepository; @Mock private CustomerRepository customerRepository; @Mock private AccountHelper accountHelper; @InjectMocks private AccountService testService; @Test void testCreateAccount_ThrowsCustomerNotFound() { Account account = Account.builder() .accountType(AccountType.SAVINGS) .openingBalance(BigDecimal.valueOf(3000)) .ifsc("IFSC1") .customerId(1) .build(); // 模拟调用checkAccountTypeForCustomer时抛出异常 doThrow(new CustomerNotFoundException("604", Message.CUSTOMER_NOT_FOUND)) .when(accountHelper).checkAccountTypeForCustomer(account); // 断言会抛出异常 assertThrows(CustomerNotFoundException.class, () -> testService.createAccount(account)); // 验证AccountHelper的方法确实被Service调用 verify(accountHelper).checkAccountTypeForCustomer(account); } }
理解误区总结
你混淆了Mockito中Mock对象的作用:Mock对象是用来模拟依赖组件的行为,默认不会执行原类的真实方法逻辑。你原本以为Mock的AccountHelper会执行检查客户的逻辑,但实际上它只是一个“空壳”,不会触发任何真实逻辑,自然不会抛出异常。
内容的提问来源于stack exchange,提问作者Pavithra
相关产品推荐
相关产品推荐

