当前位置: 首页 > 测试知识 > JUnit测接口性能怎么做?完整脚本编写示例
JUnit测接口性能怎么做?完整脚本编写示例
2026-04-27 作者cwb 浏览次数4

用JUnit做接口性能测试是用循环或 @RepeatedTest多次调用目的接口,记录每次耗时,然后在测试中统计平均值、P99 等标准,并断言这些标准是不是达标。轻松嵌入CI流水线,每次创建都自动检查接口延迟有没有问题。


两个可以直接运行的示例:

使用 java.net.http.HttpClient(Java 11+,推荐)

使用 HttpURLConnection(Java 8 兼容)


1. 准备工作(Maven 依赖)

只需要引入 JUnit 5:


xml

<dependency>

    <groupId>org.junit.jupiter</groupId>

    <artifactId>junit-jupiter</artifactId>

    <version>5.10.2</version>

    <scope>test</scope>

</dependency>


2. 根据 Java 11+ HttpClient


java

import org.junit.jupiter.api.*;


import java.net.URI;

import java.net.http.HttpClient;

import java.net.http.HttpRequest;

import java.net.http.HttpResponse;

import java.time.Duration;

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;


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


@TestInstance(TestInstance.Lifecycle.PER_CLASS)

class ApiPerformanceTest {


    // ========== 待测接口 ==========

    private static final String API_URL = "https://jsonplaceholder.zmtests.com/posts/1";

    private static final int WARMUP_COUNT = 5;      // 预热次数

    private static final int TEST_COUNT = 50;        // 正式测试次数

    private static final double MAX_AVG_MS = 500;    // 平均延迟阈值(ms)

    private static final double MAX_P99_MS = 1000;   // P99 阈值(ms)


    // 全局 HTTP 客户端,复用连接

    private final HttpClient client = HttpClient.newBuilder()

            .connectTimeout(Duration.ofSeconds(5))

            .build();


    // 存储每次成功请求的延迟(ns)

    private final List<Long> latencies = Collections.synchronizedList(new ArrayList<>());


    @BeforeAll

    void warmUp() throws Exception {

        System.out.println("=== Warming up ===");

        for (int i = 0; i < WARMUP_COUNT; i++) {

            callApi();

        }

    }


    /**

     * 重复执行 50 次正式测试,每次测量 API 请求耗时

     */

    @RepeatedTest(value = TEST_COUNT, name = "API请求 {currentRepetition}/{totalRepetitions}")

    void singleRequestLatency() throws Exception {

        long start = System.nanoTime();

        HttpResponse<String> response = callApi();

        long latencyNanos = System.nanoTime() - start;


        // 只统计 2xx/3xx 的成功请求

        if (response.statusCode() >= 200 && response.statusCode() < 400) {

            latencies.add(latencyNanos);

            System.out.printf("请求耗时: %.2f ms (status %d)%n",

                    latencyNanos / 1_000_000.0, response.statusCode());

        } else {

            System.err.printf("非成功状态码: %d%n", response.statusCode());

        }


        // 每次请求都检查状态码(功能回归的同时测性能)

        assertEquals(200, response.statusCode(), "HTTP 状态码异常");

    }


    /**

     * 重要 HTTP 请求方法

     */

    private HttpResponse<String> callApi() throws Exception {

        HttpRequest request = HttpRequest.newBuilder()

                .uri(URI.create(API_URL))

                .timeout(Duration.ofSeconds(5))

                .GET()

                .build();

        return client.send(request, HttpResponse.BodyHandlers.ofString());

    }


    @AfterAll

    void reportAndAssert() {

        assertFalse(latencies.isEmpty(), "未收集到任何成功的响应数据");


        // 计算统计值

        double avg = latencies.stream().mapToLong(Long::longValue).average().orElse(0);

        long min = latencies.stream().mapToLong(Long::longValue).min().orElse(0);

        long max = latencies.stream().mapToLong(Long::longValue).max().orElse(0);

        double p99 = percentile(latencies, 99.0);


        // 输出统计报告

        System.out.println("\n===== API 延迟统计 =====");

        System.out.printf("样本数: %d%n", latencies.size());

        System.out.printf("平均: %.2f ms%n", avg / 1_000_000.0);

        System.out.printf("最小: %.2f ms%n", min / 1_000_000.0);

        System.out.printf("最大: %.2f ms%n", max / 1_000_000.0);

        System.out.printf("P99:  %.2f ms%n", p99 / 1_000_000.0);


        // 性能断言:如果超出阈值则测试失败

        assertTrue(avg / 1_000_000.0 < MAX_AVG_MS,

                String.format("平均延迟 %.2f ms 超过阈值 %.2f ms", avg / 1_000_000.0, MAX_AVG_MS));

        assertTrue(p99 / 1_000_000.0 < MAX_P99_MS,

                String.format("P99 延迟 %.2f ms 超过阈值 %.2f ms", p99 / 1_000_000.0, MAX_P99_MS));

    }


    // 简单百分位数计算

    private double percentile(List<Long> list, double percentile) {

        List<Long> sorted = new ArrayList<>(list);

        sorted.sort(Long::compareTo);

        int index = (int) Math.ceil(percentile / 100.0 * sorted.size()) - 1;

        return sorted.get(Math.max(index, 0));

    }

}


代码:

@RepeatedTest 控制执行次数,每次重复都是一次独立的测试记录,便于定位偶发问题。

使用 List<Long> latencies 收集所有延迟数据,在 @AfterAll 统一分析。

预热 (@BeforeAll) 可避免 JIT 编译、DNS 缓存等初期原因干扰结果。

System.nanoTime() 提供纳秒精度,适合毫秒级延迟测量。

性能断言使测试直接“红/绿”,方便集成到 CI 中作为质量门禁。

3. Java 8兼容的HttpURLConnection版本

如果你的环境仍在使用 Java 8,也可以使用原生的 HttpURLConnection:


java

import org.junit.jupiter.api.*;


import java.io.BufferedReader;

import java.io.InputStreamReader;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;


@TestInstance(TestInstance.Lifecycle.PER_CLASS)

class ApiPerformanceJava8Test {


    private static final String API_URL = "https://jsonplaceholder.zmtests.com/posts/1";

    private static final int WARMUP = 5;

    private static final int ITERATIONS = 50;


    private final List<Long> latencies = Collections.synchronizedList(new ArrayList<>());


    @BeforeAll

    void warmUp() throws Exception {

        for (int i = 0; i < WARMUP; i++) doRequest();

    }


    @RepeatedTest(ITERATIONS)

    void testLatency() throws Exception {

        long start = System.nanoTime();

        int status = doRequest();

        long latency = System.nanoTime() - start;

        latencies.add(latency);

        assertEquals(200, status);

    }


    private int doRequest() throws Exception {

        URL url = new URL(API_URL);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setConnectTimeout(3000);

        conn.setReadTimeout(3000);

        conn.setRequestMethod("GET");


        int status = conn.getResponseCode();

        // 消耗响应体,保证连接可复用

        try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {

            while (br.readLine() != null) { /* 读空 */ }

        }

        conn.disconnect();

        return status;

    }


    @AfterAll

    void report() {

        // ...统计和断言思路同上,略...

    }

}


4. 运行方式

IDE:直接右键类名 → Run 'ApiPerformanceTest'。


命令行(Maven):


bash

mvn test -Dtest=ApiPerformanceTest


自定义被测接口:只需修改 API_URL 常量,或通过系统属性 ${api.url} 动态注入。


5. 注意事项

JUnit 是单用户串行测试:得到的是单线程下的接口延迟,可用于开发阶段的性能回归检测,但不代表高并发下的真实承载能力。如需压力测试,请使用 JMeter、Gatling 等专业工具。

统计有效性:建议预热至少5次,正式测试30~50次以上,避免个别极端值影响决定。

灵活性:如果不想用 @RepeatedTest,可以在一个 @Test 方法内写 for 循环,思路完全相同,但报告会只显示一个测试用例。

超时控制:生产代码中必须设置连接超时和读取超时,防止网络问题导致测试卡死。


将性能验收直接融入单元/集成测试,每次提交都能自动证实接口延迟是不是在约定范围内,及时发现由代码变更或环境问题引起的性能劣化。


文章标签: 软件测试 测试工具
咨询软件测试