← 返回 学习 列表

JUnit

2026-05-18 20:28:02

JUnit

依赖

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

确保main文件和test文件结构一致

基础语法

// Main
package pk;

public class Main {
    public static int preSum(int n){
        int res=0;
        for(int i=1;i<=n;i++){
            res+=i;
        }
        return res;
    }
    public int preTime(int n){
        int res=1;
        for(int i=1;i<=n;i++){
            res*=i;
        }
        return res;
    }
}
// Test
package pk;

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

public class TestPreSum {

    @Test
    void testPreSum() {
        int res1 = Main.preSum(3);               // 调用静态方法
        assertEquals(6, res1);             // 期望值在前,实际值在后

        Main main=new Main();
        int res2=main.preTime(3);                // 实例方法
        assertEquals(6,res2);
    }
}

常用方法

  • assertTrue(): 期待结果为true
  • assertFalse(): 期待结果为false
  • assertNotNull(): 期待结果为非null
  • assertArrayEquals(): 期待结果为数组并与期望数组每个元素的值均相等
  • 使用浮点数时,由于浮点数无法精确地进行比较,因此,我们需要调用assertEquals(double expected, double actual, double delta)这个重载方法,指定一个误差值:

    java assertEquals(0.1, Math.abs(1 - 9 / 10.0), 0.0000001);

使用@BeforeEach@AfterEach

如果测试对象需要初始化,或者测试完需要清理,可以用@BeforeEach@AfterEach@BeforeAll@AfterAll避免每个测试方法都编写初始化语句

// Main
public class Calculator {
    private long n = 0;

    public long add(long x) {
        n = n + x;
        return n;
    }

    public long sub(long x) {
        n = n - x;
        return n;
    }
}

// Test
public class CalculatorTest {

    Calculator calculator;

    @BeforeEach
    public void setUp() {
        this.calculator = new Calculator();
    }
    @AfterEach
    public void tearDown() {
        this.calculator = null;
    }
    @Test
    void testAdd() {
        assertEquals(100, this.calculator.add(100));
        assertEquals(150, this.calculator.add(50));
        assertEquals(130, this.calculator.add(-20));
    }
    @Test
    void testSub() {
        assertEquals(-100, this.calculator.sub(100));
        assertEquals(-150, this.calculator.sub(50));
        assertEquals(-130, this.calculator.sub(-20));
    }
}
  • 实例变量@BeforeEach中初始化,在@AfterEach中清理,它们在各个@Test方法中互不影响,因为是不同的实例;
  • 静态变量@BeforeAll中初始化,在@AfterAll中清理,它们在各个@Test方法中均是唯一实例,会影响各个@Test方法。
  • 大多数情况下,使用@BeforeEach@AfterEach

异常测试

JUnit提供assertThrows()来期望捕获一个指定的异常

// Main
public class Calculator {
    public static int divide(int a, int b) {
        if (b == 0) throw new IllegalArgumentException("除数不能为0");
        if (a < 0 || b < 0) throw new NegativeNumberException("不支持负数");
        return a / b;
    }
}
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {

    @Test
    void testDivideByZero() {
        assertThrows(
        IllegalArgumentException.class,     // 第一个参数,期望捕获的异常类
        () -> Calculator.divide(10, 0)      // 第二个参数.函数式编程,待测试的方法 
        );    
    }
        // 不同的异常写不同的测试
    @Test
    void testDivideWithNegative() {
        assertThrows(NegativeNumberException.class, 
                     () -> Calculator.divide(-5, 2));
    }

参数化测试

依赖

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

用 @ParameterizedTest 替代 @Test,再配合一个参数源注解提供测试数据

参数源常用@MethodSourceCsvFileSource

  • 使用 @MethodSource

    ```java // Main package pk;

    public class Main { public static int preSum(int n){ int res=0; for(int i=1;i<=n;i++){ res+=i; } return res; } } ```

    @MethodSource传入提供数据的方法名(String)

    ```java // test package pk;

    import ...

    public class TestPreSum {

    @ParameterizedTest
    @MethodSource("preSumDataProvider")          // 方法名
    void testPreSum(int n,int expected) {        // 形参传入测试所需参数和预期值
        assertEquals(expected,Main.preSum(n));
    }
    
    // 静态返回Stream<Arguments>
    static Stream<Arguments> preSumDataProvider(){  
        return Stream.of(                           // 使用工厂方法
                // 传入所需参数和预期结果
                Arguments.of(0,0),
                Arguments.of(1,1),
                Arguments.of(2,3),
                Arguments.of(3,6)
        );
    }
    

    } ```

  • 使用 @CsvFileSource

    假设在 src/test/resources/test-data.csv 文件中写入测试数据:

    java n,expected 0,0 1,1 2,3 3,6 5,15

    @CsvFileSource传入

    • resources = "/test-data.csv"路径规则和classpath读取资源一致
    • numLinesToSkip = 1 (需要跳过的首行数)
    • 默认用逗号分隔,可以用 delimiterString = "|" 指定其他分隔符

    编写测试方法:

    ```java package pk;

    import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvFileSource;

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

    public class CalculatorTest {

    @ParameterizedTest
    @CsvFileSource(resources = "/test-data.csv", numLinesToSkip = 1)
    void testSumWithCsvFile(int n, int expected) {
        assertEquals(expected, Calculator.sum(n));
    }
    

    } ```

评论

2026-05-08 15:52:41 作者
湿哒哒