Junit 代码示例

assertEquals

@Test  
@DisplayName("Simple multiplication should work")  
public void testMultiply() {  
    assertEquals(20, calculator.multiply(4, 5),  
    "Regular multiplication should work");  
}

assertTrue

assertTrue('a' < 'b', () -> "optional failure message");

assertFalse

assertFalse('a' > 'b', () -> "optional failure message");

assertNotNull

assertNotNull(yourObject, "optional failure message");

assertNull

assertNull(yourObject, "optional failure message");

Test for exceptions

@Test 
void ensureThatFellowsStayASmallGroup() { 
    List<TolkienCharacter> fellowship = dataService.getFellowship(); 
    assertThrows(IndexOutOfBoundsException.class, () -> fellowship.get(20)); 
}

或是

@Test  
@DisplayName("Set age with negative number")  
public void testSetAgeWithNegativeNumber() {  
    Throwable exception = assertThrows(IllegalArgumentException.class,  
        () -> calculator.setAge(-1));  
    assertEquals("Age must be a positive number", exception.getMessage());  
}

assertAll

@Test 
void groupedAssertions() { 
    Address address = new Address(); 
    assertAll("address name", 
              () -> assertEquals("John", address.getFirstName()), 
              () -> assertEquals("User", address.getLastName()) 
    ); 
}

与不用 assertAll, 直接写两个 assertEquals 的区别

@Test 
void groupedAssertions() { 
    Address address = new Address(); 
    assertEquals("John", address.getFirstName());
    assertEquals("User", address.getLastName()); 
}

不用 assertAll,如果执行到一个断言判断失败的时候,就会停止执行之后的测试代码;使用 assertAll,可以执行方法中所有断言,无论成功失败。

timeout

判断方法执行是否超时:

@Test  
@DisplayName("Method's execution time should be less then 1 second")  
public void testMultiplyExecuteTime() {  
    int result = assertTimeout(Duration.ofSeconds(1), 
        () -> calculator.multiply(42424, 24));  
    assertEquals(1018176, result);  
}

另有 assertTimeoutPreemptively 方法:如果超时了,方法还没有返回,则立即中断执行。

关闭测试

方案一 @Disabled注解:

使用 @Disabled || @Disabled("msg") 注解关闭关闭测试。

方案二 assumeFalse 判断:

Assumptions.assumeFalse(System.getProperty("os.name").contains("Linux"));

可以使用 assumeFalse 方法对条件进行判断,如果参数为 true,则不执行下面测试。

动态检查(Dynamic Test)

@TestFactory 方法必须返回 DynamicNode 实例的 StreamCollectionIterableIterator

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
 
import java.util.Arrays;
import java.util.stream.Stream;
 
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
 
class DynamicTestCreationTest {
 
    @TestFactory
    Stream<DynamicTest> testDifferentMultiplyOperations() {
        MyClass tester = new MyClass();
        int[][] data = new int[][] { { 1, 2, 2 }, { 5, 3, 15 }, { 121, 4, 484 } };
        return Arrays.stream(data).map(entry -> {
            int m1 = entry[0];
            int m2 = entry[1];
            int expected = entry[2];
            return dynamicTest(m1 + " * " + m2 + " = " + expected, () -> {
                assertEquals(expected, tester.multiply(m1, m2));
            });
        });
    }
 
    // class to be tested
    class MyClass {
        public int multiply(int i, int j) {
            return i * j;
        }
    }
}

参数化测试(parameterized test)

如果待测试的输入和输出是一组数据,可以使用参数化测试。

使用 @ParameterizedTest 注解来标识参数化测试方法,提供的数据需要是静态的:

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
 
public class UsingParameterizedTest {
 
    public static int[][] data() {
        return new int[][] { { 1 , 2, 2 }, { 5, 3, 15 }, { 121, 4, 484 } };
    }
 
    @ParameterizedTest
    @MethodSource(value =  "data")
    void testWithStringParameter(int[] data) {
        MyClass tester = new MyClass();
        int m1 = data[0];
        int m2 = data[1];
        int expected = data[2];
        assertEquals(expected, tester.multiply(m1, m2));
    }
 
    // class to be tested
    class MyClass {
        public int multiply(int i, int j) {
            return i * j;
        }
    }
}

参数提供

参数化测试有多种提供测试参数的方法:

@ValueSource 注解:

@ValueSource(ints = { 1, 2, 3 })

参数以数组方式传入,支持 Stringintlongdouble 类型。

@EnumSource 注解:

@EnumSource(value = Months.class, names = {"JANUARY", "FEBRUARY"})

传入枚举类

@MethodSource 注解:

@MethodSource(names = "genTestData")

传入静态方法

@CsvSource 注解:

@CsvSource({ "foo, 1", "'baz, qux', 3" })

传入 CSV 格式

@ArgumentSource 注解:

@ArgumentsSource(MyArgumentsProvider.class)

使用类的方式提供数据,该类需实现 ArgumentsProvider 接口。