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

如何用Mockito测试写法糟糕的void方法processData的过滤规则?

如何用Mockito测试这个耦合严重的processData方法并验证过滤规则?

这个方法确实把DB操作硬编码得死死的,耦合性拉满,但咱们用Mockito还是能搞定测试的。核心思路就是mock掉所有DB的静态调用,同时构造针对性的测试数据来验证过滤逻辑。下面一步步来拆解:

1. 明确测试核心目标

我们要验证两件关键事情:

  • DB操作的执行顺序完全符合预期:先连DB1、取原始数据,再连DB2、插入过滤后的数据
  • 过滤规则生效:只有passesFilter为true的对象才会被最终插入DB2

2. 准备测试依赖

确保你的测试依赖里包含:

  • JUnit 5(或JUnit 4,根据项目情况选)
  • Mockito核心包 + Mockito-inline包(因为要mock静态类,必须用inline扩展)

3. 编写测试的具体步骤

3.1 静态Mock DB类

因为DB的方法都是静态调用,所以得用Mockito.mockStatic来创建静态mock,这样我们才能完全控制它的返回值,后续也能验证调用行为。

3.2 构造测试用的原始数据

创建一批测试对象,故意包含符合过滤条件和不符合的实例,这样才能清晰验证过滤效果。比如假设你的数据对象是DataObject(换成你实际的类名就行):

DataObject validObj1 = new DataObject();
validObj1.passesFilter = true;
DataObject validObj2 = new DataObject();
validObj2.passesFilter = true;
DataObject invalidObj = new DataObject();
invalidObj.passesFilter = false;
List<DataObject> rawData = Arrays.asList(validObj1, invalidObj, validObj2);

3.3 模拟DB的行为

让DB.getRawData()返回我们构造好的测试数据,至于connectToDB1、connectToDB2这类无返回值的方法,我们不需要模拟返回,只需要后续验证调用即可。

3.4 调用目标方法

实例化processData所在的类,直接调用这个void方法。

3.5 验证逻辑正确性

  • 验证DB调用顺序:必须严格按照connectToDB1() → getRawData() → connectToDB2() → insertProcessedData()的顺序执行
  • 验证插入的数据:insertProcessedData()的参数必须是只包含两个有效对象的列表

4. 完整测试代码示例

import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import static org.mockito.Mockito.*;
import java.util.Arrays;
import java.util.List;

class DataProcessorTest { // 替换成processData所在类的测试类名

    @Test
    void processData_ShouldFilterInvalidObjectsAndFollowDBOrder() {
        // 1. 构造测试数据
        DataObject validObj1 = new DataObject();
        validObj1.passesFilter = true;
        DataObject validObj2 = new DataObject();
        validObj2.passesFilter = true;
        DataObject invalidObj = new DataObject();
        invalidObj.passesFilter = false;
        List<DataObject> rawData = Arrays.asList(validObj1, invalidObj, validObj2);
        List<DataObject> expectedProcessedData = Arrays.asList(validObj1, validObj2);

        // 2. 静态Mock DB类(try-with-resources自动关闭mock)
        try (MockedStatic<DB> mockedDB = mockStatic(DB.class)) {
            // 3. 模拟DB.getRawData返回测试数据
            mockedDB.when(DB::getRawData).thenReturn(rawData);

            // 4. 调用目标方法
            DataProcessor target = new DataProcessor(); // 替换成processData所在类的实例
            target.processData();

            // 5. 验证调用顺序和参数
            InOrder inOrder = inOrder(mockedDB);
            inOrder.verify(DB::connectToDB1).times(1);
            inOrder.verify(DB::getRawData).times(1);
            inOrder.verify(DB::connectToDB2).times(1);
            inOrder.verify(DB::insertProcessedData).withArguments(expectedProcessedData).times(1);
        }
    }

    // 假设的DataObject类,根据实际业务替换
    static class DataObject {
        boolean passesFilter;
    }
}

5. 额外注意事项

  • 如果passesFilter是方法(比如obj.passesFilter())而不是属性,那你需要mock每个测试对象的这个方法,返回对应的布尔值:
    DataObject validObj1 = mock(DataObject.class);
    when(validObj1.passesFilter()).thenReturn(true);
    
  • 顺带提一句:这个方法的设计确实不够优雅,后续建议重构——把DB操作抽象成接口,通过依赖注入的方式传入类中,这样就不用搞静态mock了,测试会更简洁易维护。不过当前先把测试搞定再说~

内容的提问来源于stack exchange,提问作者Noob

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:26:51