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

如何用Mockito模拟Mono.from(commandResult).block()?MongoDB响应式单元测试

解决方法

要模拟Mono.from(commandResult).block()的行为,核心是让db.runCommand(bsonDocument)返回预定义的Publisher<Document>(比如Mono),这样Mono.from()会直接复用这个流,block()就能得到预期结果。同时因为目标方法是私有方法,你可以通过测试调用它的公共方法,或者用反射直接调用私有方法完成测试。

步骤1:确保被测类依赖可注入

先让被测类通过构造函数注入MongoClient,这样才能用Mockito mock这个依赖:

public class MongoCommandHandler {
    private final MongoClient mongoClient;

    // 构造函数注入MongoClient
    public MongoCommandHandler(MongoClient mongoClient) {
        this.mongoClient = mongoClient;
    }

    // 你的私有方法
    private Document runCommand(final String command) {
        final MongoDatabase db = mongoClient.getDatabase("admin");
        final Bson bsonDocument = Document.parse(command).toBsonDocument();
        final Publisher<Document> commandResult = db.runCommand(bsonDocument);
        return Mono.from(commandResult).block();
    }

    // 调用私有方法的公共方法(优先测试公共方法)
    public Document executeAdminCommand(String command) {
        return runCommand(command);
    }
}

步骤2:编写Mockito测试用例

注意:MongoDatabase是final类,Mockito默认无法mock,需要引入mockito-inline依赖支持final类的mock。

测试公共方法(推荐)

通过调用公共方法间接覆盖私有方法:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import org.bson.Bson;
import org.bson.Document;
import reactor.core.publisher.Mono;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class MongoCommandHandlerTest {

    @Mock
    private MongoClient mongoClient;

    @Mock
    private MongoDatabase mongoDatabase;

    @Test
    void executeAdminCommand_ShouldReturnExpectedResult() {
        // 1. 准备预期返回的文档
        Document expectedDoc = new Document("ok", 1.0).append("msg", "command executed");

        // 2. 配置mock行为
        when(mongoClient.getDatabase("admin")).thenReturn(mongoDatabase);
        // 让runCommand返回预定义的Mono,确保Mono.from().block()能拿到预期数据
        when(mongoDatabase.runCommand(any(Bson.class))).thenReturn(Mono.just(expectedDoc));

        // 3. 创建被测实例并调用方法
        MongoCommandHandler handler = new MongoCommandHandler(mongoClient);
        Document actualDoc = handler.executeAdminCommand("{ping: 1}");

        // 4. 验证结果
        assertEquals(expectedDoc, actualDoc);
    }
}

直接测试私有方法(仅特殊场景使用)

如果必须直接测试私有方法,可通过Java反射调用:

import java.lang.reflect.Method;

@Test
void testPrivateRunCommand() throws Exception {
    // 准备mock数据和配置
    Document expectedDoc = new Document("ok", 1.0);
    when(mongoClient.getDatabase("admin")).thenReturn(mongoDatabase);
    when(mongoDatabase.runCommand(any(Bson.class))).thenReturn(Mono.just(expectedDoc));

    MongoCommandHandler handler = new MongoCommandHandler(mongoClient);

    // 通过反射获取并调用私有方法
    Method runCommandMethod = MongoCommandHandler.class.getDeclaredMethod("runCommand", String.class);
    runCommandMethod.setAccessible(true);
    Document actualDoc = (Document) runCommandMethod.invoke(handler, "{ping: 1}");

    assertEquals(expectedDoc, actualDoc);
}

关键说明

  • 无需单独mock Mono.from().block(),只需让db.runCommand返回包含预期数据的Mono,Mono.from()会直接复用这个流,block()自然能得到目标结果。
  • 单元测试优先覆盖公共方法,私有方法的逻辑应通过公共接口的测试验证,避免依赖私有方法的实现细节。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 03:21:00