如何用Mockito测试包含CollectionUtils.filter的Service方法?
如何用Mockito测试包含CollectionUtils.filter的Service方法?
问题背景
你要测试的Service方法是这样的:
@Override @Transactional(readOnly = true) public Collection<Account> searchAccounts(String partOfName) { Collection<Account> accounts = accountDao.getAll(); CollectionUtils.filter(accounts, account -> account.getName().toLowerCase().contains(partOfName.toLowerCase()) || account.getSurname().toLowerCase().equalsIgnoreCase(partOfName.toLowerCase())); return accounts; }
目前你的测试代码只验证了accountDao.getAll()被调用一次,但完全没覆盖核心的过滤逻辑,还在纠结要不要MockCollectionUtils.filter对吧?
要不要Mock CollectionUtils.filter?
答案是不需要。CollectionUtils.filter是Apache Commons的静态工具类方法,它的逻辑是确定的——就是按你传入的Predicate过滤集合。咱们的测试目标是验证Service的业务逻辑:从Dao拿到数据后,能不能正确过滤出符合partOfName条件的账户。如果Mock了这个方法,就等于跳过了核心逻辑的验证,测试也就失去意义了。
完整测试步骤
咱们一步步来完善测试:
- 准备测试数据:创建几个Account对象,有的匹配搜索关键词,有的不匹配,模拟Dao返回的数据集。
- Mock Dao的行为:让
accountDao.getAll()返回我们准备好的测试数据。 - 调用目标方法:执行
service.searchAccounts(),传入测试用的关键词。 - 验证结果正确性:检查返回的集合是不是只包含符合条件的Account。
- 验证Dao的调用:确保
accountDao.getAll()确实被调用了一次(这部分你已经写了,保留就行)。
完整测试代码示例
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.Collection; @ExtendWith(MockitoExtension.class) public class AccountServiceTest { @Mock private AccountDao accountDao; // 假设这是你的Dao接口 @InjectMocks private AccountService service; // 你的Service类 @Test public void searchAccountsByPartOfName_shouldReturnMatchingAccounts() { // 1. 准备测试数据 Account account1 = new Account("TestUser", "Smith"); // 匹配"test" Account account2 = new Account("John", "Doe"); // 不匹配"test" Account account3 = new Account("Alice", "Testson"); // 匹配"test" Collection<Account> mockAccounts = new ArrayList<>(); mockAccounts.add(account1); mockAccounts.add(account2); mockAccounts.add(account3); // 2. Mock Dao的getAll方法 when(accountDao.getAll()).thenReturn(mockAccounts); // 3. 调用目标方法 Collection<Account> result = service.searchAccounts("test"); // 4. 验证结果:应该只有account1和account3,数量为2 assertEquals(2, result.size()); assertTrue(result.contains(account1)); assertTrue(result.contains(account3)); assertFalse(result.contains(account2)); // 5. 验证Dao的调用次数 verify(accountDao, times(1)).getAll(); } // 额外测试:验证大小写不敏感的逻辑 @Test public void searchAccountsByPartOfName_caseInsensitive() { Account account = new Account("TestUser", "Smith"); Collection<Account> mockAccounts = new ArrayList<>(); mockAccounts.add(account); when(accountDao.getAll()).thenReturn(mockAccounts); Collection<Account> result = service.searchAccounts("TEST"); assertEquals(1, result.size()); assertTrue(result.contains(account)); verify(accountDao, times(1)).getAll(); } }
补充说明
如果你的项目用的是Mockito 3.4+,确实可以用Mockito-inline来Mock静态方法,但这里完全没必要——我们要测试的是Service的业务逻辑是否正确,而不是工具类的正确性。工具类本身应该由它自己的测试来覆盖,咱们只需要确保Service正确使用了它就行。
内容的提问来源于stack exchange,提问作者diofloyk
相关产品推荐
相关产品推荐

