Junit 高级-ApiHug准备-测试篇-011

     🤗 ApiHug × {Postman|Swagger|Api...} = 快↑ 准√ 省↓

  1. GitHub - apihug/apihug.com: All abou the Apihug   
  2. apihug.com: 有爱,有温度,有质量,有信任
  3. ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace

涉及到 Junit5 一些深度不太常用的功能, 例子在:advancedopen in new window

#顺序

JUnit 5 支持下面几种 MethodOrderer:

  1. MethodName – 按照函数名字的字母排序。
  2. DisplayName – 按照显示名词的字母排序。
  3. OrderAnnotation – 按照 @Order annotation 排序,同order 排序方式可能不一致(所以尽量order 是散列的, 未标注的排最后面。
  4. Random – 随机排序 种子值可以通过系统配置: junit.jupiter.execution.order.random.seed 来配置。
  5. Custom – 定制扩展的排序类。

MethodNameOrderedTestsopen in new window 例子:

#MethodName

@TestMethodOrder(MethodOrderer.MethodName.class)
public class MethodNameOrderedTests 
{
    @Test
    void testE() {
        assertTrue(true);
    }
}

#DisplayName


@TestMethodOrder(MethodOrderer.DisplayName.class)
public class DisplayNameOrderedTests
{
    @DisplayName("5")
    @Test
    void testE() {
        assertTrue(true);
    }
}

#OrderAnnotation


@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class OrderAnnotationTests {
  @Order(5)
  @Test
  void testE() {
    assertTrue(true);
  }
}

#Random

修改 junit-platform.properties

junit.jupiter.execution.order.random.seed=9999

这个测试类, 每次执行的结果顺序都讲不一样!


@TestMethodOrder(MethodOrderer.Random.class)
public class RandomOrderedTests {
  @Test
  void testE() {
    assertTrue(true);
  }
}

#Custom

比如一个实现按照接口是否被 Deprecated, 排到最后进行测试:


public class DeprecatedInEndTestOrder implements MethodOrderer {

  private Comparator<MethodDescriptor> comparator =
      Comparator.comparing(md -> md.getMethod().isAnnotationPresent(Deprecated.class));

  @Override
  public void orderMethods(MethodOrdererContext context) {

    context.getMethodDescriptors().sort(comparator);
  }
}

然后参考测试用例:


@TestMethodOrder(DeprecatedInEndTestOrder.class)
public class CustomOrderTests {
  @Test
  @Deprecated
  void testC() {
    assertTrue(true);
  }

  @Test
  void testA() {
    assertTrue(true);
  }
}

当然也有正对,测试类自己的排序,这里不再赘述, 参考样例代码。

默认配置: junit.jupiter.testclass.order.default = org.junit.jupiter.api.ClassOrderer$OrderAnnotation


@TestClassOrder(ClassOrderer.OrderAnnotation.class)
class OrderedTestClassesExample {

  @Nested
  @Order(1)
  class SetupTests {

    @Test
    void test1() {}
  }

  @Nested
  @Order(2)
  class AppFlowTests {

    @Test
    void test2() {}
  }
}

#Temp Dir

@TempDir 尚在实验功能open in new window 但是在一些场景下非常有用。

@TempDir 可以使用在方法参数, 类参数, 静态方法,可以用于构建 Fixture, 举个例子 测试目录open in new window


@Test
void tempDirectoryTestOne(@TempDir Path tempDir) throws IOException {
    Path tempFile = tempDir.resolve("test.txt");

    List<String> lines = Arrays.asList("dearxue.com");

    Files.write(tempFile, Arrays.asList("dearxue.com"));

    Assertions.assertTrue(Files.exists(tempFile), "Temp File should have been created");
    Assertions.assertEquals(Files.readAllLines(tempFile), lines);
}

@TempDir 作为成员变量, 那么每个测试用例都会创建一个新的临时测试目录, 然后再删除参考 TempDirTest2


test1 dir:  C:\Users\dearxue\AppData\Local\Temp\junit3449074755074304313
test2 dir:  C:\Users\dearxue\AppData\Local\Temp\junit7411092462858685015

@TempDir 作为静态成员变量, 和成员变量不一样, 这里一个测试类中不同测试方法会共享一个目录。

#测试名称

在一些场景下你希望获取测试名词, 可以通过 TestInfo 上下文获得 gettestname 例子open in new window


@Test
void givenNumbers_whenOddCheck_thenVerify(TestInfo testInfo) {
    System.out.println("displayName = " + testInfo.getDisplayName());
    int number = 5;
    assertTrue(oddCheck(number));
}

获得输出:

displayName = givenNumbers_whenOddCheck_thenVerify(TestInfo)

参数化场景可以通过 @BeforeEach 获得:

private TestInfo testInfo;

  @BeforeEach
  void init(TestInfo testInfo) {
    this.testInfo = testInfo;
  }

  private boolean oddCheck(int number) {
    return (number % 2 != 0);
  }

  @ParameterizedTest(name = "givenNumbers_whenOddCheck_thenVerify{0}")
  @ValueSource(ints = {1, 3, 5, -3, 15})
  void givenNumbers_whenOddCheck_thenVerify(int number) {
    System.out.println("displayName = " + testInfo.getDisplayName());
    assertTrue(oddCheck(number));
  }

输出为:


displayName = givenNumbers_whenOddCheck_thenVerify5
displayName = givenNumbers_whenOddCheck_thenVerify-3
displayName = givenNumbers_whenOddCheck_thenVerify3
displayName = givenNumbers_whenOddCheck_thenVerify1
displayName = givenNumbers_whenOddCheck_thenVerify15

#Test Instance

默认情况下, Junit 会为每个测试方法创建一个新的instance,这样保持状态的隔离:


class AdditionTest {

    private int sum = 1;

    @Test
    void addingTwoReturnsThree() {
        sum += 2;
        assertEquals(3, sum);
    }

    @Test
    void addingThreeReturnsFour() {
        sum += 3;
        assertEquals(4, sum);
    }
}

比如这个测试用例, 两个测试方法执行前, 新的事例被创建, sum 被初始化为1, 所以每个方法都能成立。

如果共享一个事例, 那么第二个方法会失败。

但是在一些情况下我们需要, 共享这些变量, 比如一些非常耗时的操作, 这个时候 TestInstance 派上用场了。

@TestInstance 两种模式一个是:LifeCycle.PER_METHOD (默认的), 另外一个是LifeCycle.PER_CLASS。

在 PER_CLASS 模式下, 我们可以看到下面例子的变量和方法都不是 static 但是能够照常运行。

@TestInstance(LifeCycle.PER_CLASS)
class TweetSerializerUnitTest {

    private String largeContent;

    @BeforeAll
    void setUpFixture() {
        // read the file
    }

#手动启动测试

你可以直接从 java 启动测试用例, 对整个junit 运行逐层debug,洞悉运行过程。

testRuntimeOnly("org.junit.platform:junit-platform-launcher") {
        because 'allows tests to run from IDEs that bundle older version of launcher'
}

添加依赖, 例子参考open in new window

public void runOne() {
    LauncherDiscoveryRequest request =
        LauncherDiscoveryRequestBuilder.request()
            .selectors(selectClass(FirstUnitTest.class))
            .build();
    Launcher launcher = LauncherFactory.create();
    TestPlan testPlan = launcher.discover(request);

    launcher.registerTestExecutionListeners(listener);
    launcher.execute(request);
  }

输出:


junit-5:RunJUnit5TestsFromJava.main()

Test run finished after 171 ms
[         6 containers found      ]
[         0 containers skipped    ]
[         6 containers started    ]
[         0 containers aborted    ]
[         6 containers successful ]
[         0 containers failed     ]
[        18 tests found           ]
[         0 tests skipped         ]
[        18 tests started         ]
[         0 tests aborted         ]
[        18 tests successful      ]
[         0 tests failed          ]

我们

api-hug-contact

相关推荐

  1. spring 单元测试 Junit

    2024-04-21 23:14:07       54 阅读
  2. 单元测试框架jUnit

    2024-04-21 23:14:07       62 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-21 23:14:07       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-21 23:14:07       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-21 23:14:07       82 阅读
  4. Python语言-面向对象

    2024-04-21 23:14:07       91 阅读

热门阅读

  1. 《AI聊天类工具之五——Copilot》

    2024-04-21 23:14:07       42 阅读
  2. nginx 导致websocket无法连接的解决办法

    2024-04-21 23:14:07       31 阅读
  3. Qt 使用qm文件

    2024-04-21 23:14:07       34 阅读
  4. Linux之 USB驱动框架-USB鼠标驱动源码分析(5)

    2024-04-21 23:14:07       29 阅读
  5. mysql一些语法记录

    2024-04-21 23:14:07       31 阅读