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

编程入门者求助:如何用Mockito模拟Unirest的HttpResponse对象

模拟Unirest响应进行单元测试的方案

刚入门Mockito确实会遇到静态方法模拟或者构造假响应的问题,我来一步步帮你解决:

一、优先推荐:封装HTTP请求(更易测试的实践)

直接模拟静态的Unirest.get()虽然可行,但更好的做法是把HTTP调用逻辑封装成一个独立的服务类,这样既符合依赖注入的思想,也让测试更简单。

步骤1:创建HTTP服务封装类

先写一个专门处理HTTP请求的类,把Unirest的调用逻辑移进去:

import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import kong.unirest.UnirestException;

public class ActivityHttpService {
    public HttpResponse<JsonNode> fetchActivities() throws UnirestException {
        return Unirest.get("http://111.111.111.111:8080/activity")
                .header("accept", "application/json")
                .asJson();
    }
}

步骤2:修改原类,注入这个服务

把原来的getActivites()方法所在的类,改成依赖注入ActivityHttpService:

import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import org.json.JSONArray;

public class ActivityService {
    private final ActivityHttpService httpService;

    // 构造注入,方便测试时传入模拟对象
    public ActivityService(ActivityHttpService httpService) {
        this.httpService = httpService;
    }

    public JSONArray getActivites() {
        HttpResponse<JsonNode> jsonResponse = null;
        try {
            jsonResponse = httpService.fetchActivities();
        } catch (UnirestException e) {
            System.out.println("Server is unreachable");
        }
        // 这里加个非空判断,避免空指针异常
        if (jsonResponse == null) {
            return new JSONArray();
        }
        return jsonResponse.getBody().getArray();
    }
}

步骤3:用Mockito模拟这个服务类

现在测试的时候,就可以轻松模拟ActivityHttpService的返回值了,不用管静态的Unirest:

import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import org.json.JSONArray;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

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

public class ActivityServiceTest {

    @Test
    void testGetActivities() throws Exception {
        // 1. 创建模拟的HTTP服务
        ActivityHttpService mockHttpService = Mockito.mock(ActivityHttpService.class);
        
        // 2. 构造假的JsonNode和HttpResponse
        JSONArray fakeActivities = new JSONArray("[{\"id\":1},{\"id\":2}]");
        JsonNode fakeJsonNode = Mockito.mock(JsonNode.class);
        when(fakeJsonNode.getArray()).thenReturn(fakeActivities);
        
        HttpResponse<JsonNode> fakeResponse = Mockito.mock(HttpResponse.class);
        when(fakeResponse.getBody()).thenReturn(fakeJsonNode);
        
        // 3. 让模拟服务返回假响应
        when(mockHttpService.fetchActivities()).thenReturn(fakeResponse);
        
        // 4. 初始化要测试的类,传入模拟对象
        ActivityService activityService = new ActivityService(mockHttpService);
        
        // 5. 调用方法并验证结果
        JSONArray result = activityService.getActivites();
        assertEquals(2, result.length());
        assertEquals(1, result.getJSONObject(0).getInt("id"));
    }
}

二、直接模拟Unirest静态方法(适合不想重构的场景)

如果你暂时不想重构代码,想用Mockito直接模拟静态的Unirest.get(),需要用Mockito的mockStatic方法(要求Mockito版本3.4.0+):

import kong.unirest.GetRequest;
import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import org.json.JSONArray;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class ActivityServiceTest {

    @Test
    void testGetActivitiesWithStaticMock() throws Exception {
        // 1. 构造假的响应链:GetRequest -> 带header的请求 -> 假的HttpResponse
        GetRequest mockGetRequest = Mockito.mock(GetRequest.class);
        when(mockGetRequest.header("accept", "application/json")).thenReturn(mockGetRequest);
        
        JSONArray fakeActivities = new JSONArray("[{\"id\":3},{\"id\":4}]");
        JsonNode fakeJsonNode = Mockito.mock(JsonNode.class);
        when(fakeJsonNode.getArray()).thenReturn(fakeActivities);
        
        HttpResponse<JsonNode> fakeResponse = Mockito.mock(HttpResponse.class);
        when(fakeResponse.getBody()).thenReturn(fakeJsonNode);
        when(mockGetRequest.asJson()).thenReturn(fakeResponse);
        
        // 2. 模拟Unirest的静态get方法
        try (MockedStatic<kong.unirest.Unirest> mockedUnirest = Mockito.mockStatic(kong.unirest.Unirest.class)) {
            mockedUnirest.when(() -> kong.unirest.Unirest.get("http://111.111.111.111:8080/activity"))
                    .thenReturn(mockGetRequest);
            
            // 3. 调用要测试的方法
            ActivityService activityService = new ActivityService(); // 假设原类没有注入,直接调用
            JSONArray result = activityService.getActivites();
            
            // 4. 验证结果
            assertEquals(2, result.length());
            assertEquals(3, result.getJSONObject(0).getInt("id"));
        }
    }
}

注意:静态模拟需要用try-with-resources来确保静态模拟的资源被正确释放,避免影响其他测试。

三、复用真实服务的数据

你提到的“先访问一次真实服务提取数据,后续测试复用”完全可行,步骤如下:

  1. 抓取真实数据:写一个简单的工具类或者main方法,调用一次真实的getActivites(),把返回的JSONArray转成字符串,保存到项目的src/test/resources目录下(比如activities.json)。
// 示例代码,运行一次即可
public class DataFetcher {
    public static void main(String[] args) {
        ActivityService service = new ActivityService();
        JSONArray activities = service.getActivites();
        // 把activities.toString()写入到src/test/resources/activities.json
        // 可以用Files.write来实现
    }
}
  1. 测试时读取本地数据:在测试类中读取这个JSON文件,构造假的响应:
import org.json.JSONArray;
import org.junit.jupiter.api.Test;
import java.nio.file.Files;
import java.nio.file.Paths;

public class ActivityServiceTest {

    private JSONArray loadRealActivities() throws Exception {
        // 读取本地JSON文件
        String jsonContent = new String(Files.readAllBytes(Paths.get("src/test/resources/activities.json")));
        return new JSONArray(jsonContent);
    }

    @Test
    void testGetActivitiesWithRealData() throws Exception {
        JSONArray realActivities = loadRealActivities();
        // 接下来用这个realActivities去构造假的JsonNode和HttpResponse,和前面的测试逻辑一样
        // ... 省略模拟步骤,直接用realActivities替换fakeActivities即可
    }
}

这样每次测试都用真实的历史数据,不用再访问真实服务,同时保证数据的真实性。

最后提醒一下:原代码里jsonResponse可能为null(比如UnirestException发生时),直接调用jsonResponse.getBody()会抛出空指针异常,建议加上非空判断,像我在步骤2里修改的那样。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:41:11