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

如何使用Mockito(JUnit)为无返回值方法编写测试用例?

别担心,我来帮你搞定这个无返回值方法的测试!首先咱们先把你的代码格式化一下,看起来更清晰:

import java.util.concurrent.TimeUnit;

public class Calculation {
    public void logTimeTaken(String label, long estimatedTime, int size, boolean isDebug) {
        String out = label + " took " + TimeUnit.MILLISECONDS.convert(estimatedTime, TimeUnit.NANOSECONDS) + " milliseconds for " + size + " events!";
        if (isDebug) {
            System.out.println(out);
        } else {
            System.out.println(out);
        }
    }
}

这个方法的核心行为是生成格式化的日志字符串,并通过System.out.println输出——虽然你的代码里isDebug的两个分支逻辑完全一样,但咱们还是按现有逻辑来写测试。

测试思路

因为方法没有返回值,我们需要验证它的副作用:也就是是否按预期调用了System.out.println,并且传入的参数是正确的格式化字符串。这里有两种常用的实现方式:


方式一:用Mockito静态Mock验证方法调用

从Mockito 3.4.0开始,支持静态方法的Mock,不过需要额外引入mockito-inline依赖。

1. 先准备依赖(Maven示例)
<dependencies>
    <!-- JUnit 5 核心依赖 -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
    </dependency>
    <!-- Mockito 核心 + 静态Mock支持 -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>4.11.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-inline</artifactId>
        <version>4.11.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>
2. 编写测试类
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import java.util.concurrent.TimeUnit;
import static org.mockito.Mockito.*;

public class CalculationTest {

    @Test
    void logTimeTaken_ShouldPrintCorrectMessage_WhenDebugIsEnabled() {
        // 1. 准备测试数据
        String testLabel = "数据同步";
        long testNanos = 2_000_000_000; // 2秒,转成毫秒是2000
        int testSize = 200;
        boolean isDebug = true;

        // 2. 计算预期的输出字符串
        String expectedOutput = testLabel + " took " + TimeUnit.MILLISECONDS.convert(testNanos, TimeUnit.NANOSECONDS) + " milliseconds for " + testSize + " events!";

        // 3. 静态Mock System类,用try-with-resources自动关闭Mock
        try (MockedStatic<System> mockedSystem = mockStatic(System.class)) {
            // 实例化被测试类
            Calculation calculation = new Calculation();
            // 调用待测试方法
            calculation.logTimeTaken(testLabel, testNanos, testSize, isDebug);

            // 4. 验证System.out.println是否被调用了1次,且参数是预期的字符串
            mockedSystem.verify(() -> System.out.println(expectedOutput), times(1));
        }
    }

    @Test
    void logTimeTaken_ShouldPrintCorrectMessage_WhenDebugIsDisabled() {
        String testLabel = "文件导出";
        long testNanos = 800_000_000; // 0.8秒,转成毫秒是800
        int testSize = 80;
        boolean isDebug = false;

        String expectedOutput = testLabel + " took " + TimeUnit.MILLISECONDS.convert(testNanos, TimeUnit.NANOSECONDS) + " milliseconds for " + testSize + " events!";

        try (MockedStatic<System> mockedSystem = mockStatic(System.class)) {
            Calculation calculation = new Calculation();
            calculation.logTimeTaken(testLabel, testNanos, testSize, isDebug);

            // 因为你的代码里else分支也执行println,所以同样验证调用
            mockedSystem.verify(() -> System.out.println(expectedOutput), times(1));
        }
    }
}

方式二:捕获System.out输出流验证(无需Mockito)

如果不想用静态Mock,也可以通过重定向System.out的输出流来捕获内容,直接验证输出是否符合预期:

import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class CalculationTest {

    @Test
    void logTimeTaken_ShouldOutputCorrectContent() {
        // 1. 保存原始的System.out,测试后恢复
        PrintStream originalOut = System.out;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        System.setOut(new PrintStream(outputStream));

        try {
            String testLabel = "数据处理";
            long testNanos = 1_500_000_000;
            int testSize = 150;

            Calculation calculation = new Calculation();
            calculation.logTimeTaken(testLabel, testNanos, testSize, true);

            // 注意:println会自动添加换行符,所以预期字符串要加\n
            String expectedOutput = testLabel + " took " + TimeUnit.MILLISECONDS.convert(testNanos, TimeUnit.NANOSECONDS) + " milliseconds for " + testSize + " events!\n";
            // 验证捕获到的输出是否和预期一致
            assertEquals(expectedOutput, outputStream.toString());
        } finally {
            // 恢复原始的System.out,避免影响其他测试
            System.setOut(originalOut);
        }
    }
}

额外提醒

你代码里的isDebug分支逻辑完全相同,可能是笔误(比如else分支应该用日志框架输出而不是System.out)。如果后续调整了分支逻辑,只需要对应修改测试里的验证逻辑即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:44:03