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

如何用Mockito与JUnit5编写BigQuery的JUnit测试并Mock/初始化Table

问题:Mockito+JUnit5测试BigQuery Table类Mock/初始化失败

我尝试使用Mockito和JUnit5编写BigQuery的JUnit测试用例,但无法Mock或初始化Table类,请问有可行的解决方法吗?

业务代码

private JsonStreamWriter streamWriter;

void WriteToBQ(TableName parentTable) {
        BigQuery bigquery = BigQueryOptions
                .newBuilder()
                .setProjectId(AppConstants.PROJECT_ID)
                .build()
                .getService();

        Table table = bigquery.getTable(parentTable.getDataset(), parentTable.getTable());
        Schema schema = table.getDefinition().getSchema();

        TableSchema tableSchema = BqToBqStorageSchemaConverter.convertTableSchema(schema);

        streamWriter = JsonStreamWriter.newBuilder(parentTable.toString(), tableSchema).build();
    }

我尝试过的方法

  1. 直接实例化Table失败
    尝试通过以下代码初始化Table,但TableInfo.BuilderImpl是非公共类,无法跨包使用:
table = new Table(bigquery, new TableInfo.BuilderImpl(TABLE_INFO));
  1. Mock Table类未成功
    编写了以下Mock代码,但没有效果:
bigquery = mock(BigQuery.class);
mockOptions = mock(BigQueryOptions.class);
table = mock(Table.class);
when(bigquery.getTable(any(),any())).thenReturn(table);
when(bigquery.getOptions()).thenReturn(mockOptions);

解决方案

1. 先重构业务代码(关键步骤)

问题根源是业务方法内直接创建BigQuery实例,导致测试时无法替换为Mock对象。需要把BigQuery的创建逻辑抽离,改为依赖注入:

重构后的业务代码示例(构造注入方式)

private JsonStreamWriter streamWriter;
private final BigQuery bigquery;

// 生产环境传入真实BigQuery实例,测试时传入Mock实例
public YourServiceClass(BigQuery bigquery) {
    this.bigquery = bigquery;
}

void WriteToBQ(TableName parentTable) {
        Table table = bigquery.getTable(parentTable.getDataset(), parentTable.getTable());
        Schema schema = table.getDefinition().getSchema();

        TableSchema tableSchema = BqToBqStorageSchemaConverter.convertTableSchema(schema);

        streamWriter = JsonStreamWriter.newBuilder(parentTable.toString(), tableSchema).build();
    }

如果不想修改构造方法,也可以用工厂方法抽离:

private JsonStreamWriter streamWriter;

// 默认返回真实BigQuery,测试时可重写该方法
protected BigQuery createBigQuery() {
    return BigQueryOptions
            .newBuilder()
            .setProjectId(AppConstants.PROJECT_ID)
            .build()
            .getService();
}

void WriteToBQ(TableName parentTable) {
        BigQuery bigquery = createBigQuery(); // 调用工厂方法获取实例
        // 后续逻辑不变...
}

2. 编写正确的测试用例

现在可以Mock所有依赖对象,让测试逻辑正常执行:

测试代码示例

import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class YourServiceClassTest {

    @Mock
    private BigQuery mockBigQuery;
    @Mock
    private Table mockTable;
    @Mock
    private TableDefinition mockTableDefinition;
    @Mock
    private Schema mockSchema;
    @Mock
    private JsonStreamWriter mockStreamWriter;

    // 构造注入方式初始化测试对象
    private YourServiceClass service = new YourServiceClass(mockBigQuery);

    // 工厂方法方式的初始化(如果用工厂方法重构)
    /*
    private YourServiceClass service = new YourServiceClass() {
        @Override
        protected BigQuery createBigQuery() {
            return mockBigQuery;
        }
    };
    */

    @Test
    void testWriteToBQ() {
        // 测试用TableName
        TableName testTable = TableName.of("test-project", "test-dataset", "test-table");

        // 依次Stub各层级方法的返回值
        when(mockBigQuery.getTable(eq(testTable.getDataset()), eq(testTable.getTable())))
                .thenReturn(mockTable);
        when(mockTable.getDefinition()).thenReturn(mockTableDefinition);
        when(mockTableDefinition.getSchema()).thenReturn(mockSchema);

        // 按需Mock转换逻辑和Writer构建
        TableSchema mockTableSchema = mock(TableSchema.class);
        when(BqToBqStorageSchemaConverter.convertTableSchema(mockSchema))
                .thenReturn(mockTableSchema);
        when(JsonStreamWriter.newBuilder(eq(testTable.toString()), eq(mockTableSchema)))
                .thenReturn(mock(JsonStreamWriter.Builder.class));
        when(JsonStreamWriter.newBuilder(anyString(), any(TableSchema.class)).build())
                .thenReturn(mockStreamWriter);

        // 执行测试方法
        service.WriteToBQ(testTable);

        // 验证关键方法的调用
        verify(mockBigQuery).getTable(eq(testTable.getDataset()), eq(testTable.getTable()));
        verify(mockTable).getDefinition();
        verify(mockTableDefinition).getSchema();
    }
}

为什么之前的Mock没生效?

原来的业务代码在方法内部直接new了BigQuery实例,完全没有用到测试代码中创建的mockBigQuery对象,所以所有Stub设置都不会生效。重构后让业务代码依赖外部传入的BigQuery,测试时就能替换为Mock对象了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 02:01:50