You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:27:42