jck28 - 小柒 - Junit5参数化与调度执行学习笔记2

8,超时处理

  • 使用 JUnit5 自带的超时处理,当测试用例执行时间超过设置的执行时间,那么用例结果为执行失败。
package MethodSourceDemo;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;

import java.util.concurrent.TimeUnit;

import static java.lang.Thread.sleep;

public class TimeoutTest {
    @Test
    @Timeout(5)         //设置用例的超时时间为5秒
    void timeoutDemo() throws InterruptedException {
        sleep(6000);     //设置用例休眠6秒后执行
        System.out.println("超时用例");
    }

    @Test             //没有设置超时时间的用例不受影响
    void timeoutDemo2(){
        System.out.println("超时用例2");
    }

    @Test
    //通过value参数配置数量,通过unit参数配置时间单位
    @Timeout(value = 10, unit = TimeUnit.MILLISECONDS)
    void setUp() throws InterruptedException {
        sleep(6000);
        System.out.println("超时用例33");
    }
}

9,用例显示名称
(1)@DisplayName注解定义用例名称

package MethodSourceDemo;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class DisplaynameTest {
    // 通过DisplayName注解定义
    @DisplayName("第一条用例")
    @Test
    void FirstCase(){
        System.out.println("第一条用例");
    }

    @DisplayName("第二条用例")
    @Test
    void SecondCase(){
        System.out.println("第二条用例");
    }
}

(2) 通过注解 @DisplayNameGenerator 实现生成器

  • 在测试类前加上配置 @DisplayNameGeneration(DisplayNameGenerator.Standard.class)

package MethodSourceDemo;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;

// 默认配置,不会有变化
@DisplayNameGeneration(DisplayNameGenerator.Standard.class)

public class DisplaynameTest {

    @Test
    void First_Case() {
        System.out.println("第一条用例");
    }

    @Test
    void Second_Case() {
        System.out.println("第二条用例");
    }
}

(3)通过配置文件配置

  1. 在路径 src/test/resources中添加junit-platform.properties配置文件。
  2. 在配置文件中添加对应的配置属性。
# 全局配置Display name 为连接类名与方法名
junit.jupiter.displayname.generator.default = \
 org.junit.jupiter.api.DisplayNameGenerator$IndicativeSentences

(4)配置优先级

10,嵌套测试

  • 定制化执行用例
  • 用例层级、业务关系更加清晰
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

public class NestedDemo {
    @Nested
    class AuthorityManagment{
        @Nested
        class Management{
            @Test
            void managementLogin(){
                System.out.println("管理员登录测试");
            }
            @Nested
            class ManagementDelete{
                @Test
                void deleteUser(){
                    System.out.println("删除用户");
                }
            }
        }
        @Nested
        class Client{
        }
    }
    @Nested
    class DataManagement{
        @Nested
        class CreditScore{
            @Nested
            class MortgageScore{
                @Test
                void getMortgageScore(){
                    System.out.println("房屋贷款");
                }
            }
        }
    }

}

11,执行顺序@Order

使用场景:

  • 测试用例有业务逻辑相关
  • 集成测试(主流程测试)

排序方式:

  • 方法排序
  • 类排序
  • Suite
  • 官方网站没有明确说明默认排序的具体规则

方法排序:

package orderDemo;

import org.junit.jupiter.api.*;

//设定排序方法为注解指定排序,与@Order结合一起使用
//@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
//设定排序方法为,根据DisplayName进行排序,与@DisplayName结合一起使用
//@TestMethodOrder(MethodOrderer.DisplayName.class)
//设计排序类型为随机排序
//@TestMethodOrder(MethodOrderer.Random.class)
// 设置排序类型为按方法名排序
@TestMethodOrder(MethodOrderer.MethodName.class)

public class OrderdemoTest {
    @Test
//    @Order(2)
//    @DisplayName("a用例")
    void firstTest() {
        System.out.println("第1条用例");
    }
    @Test
//    @Order(3)
//    @DisplayName("c用例")
    void TwoTest() {
        System.out.println("第2条用例");
    }
    @Test
//    @Order(1)
//    @DisplayName("b用例")
    void ThreeTest() {
        System.out.println("第3条用例");
    }
}

类排序:

image

package orderDemo;

import org.junit.jupiter.api.*;

//设定排序方法为注解指定排序,与@Order结合一起使用
//@TestClassOrder(ClassOrderer.OrderAnnotation.class)
//设定排序方法为,根据DisplayName进行排序,与@DisplayName结合一起使用
//@TestClassOrder(ClassOrderer.DisplayName.class)
//设定排序类型为随机排序
//@TestClassOrder(ClassOrderer.Random.class)
// 设置排序类型为按类名排序
//@TestClassOrder(ClassOrderer.ClassName.class)

public class ClassOrderTest {
    // 因为是多类执行,所以需要结合@Nested注解
    @Nested
    @Order(1)
//    @DisplayName("b")
    class PrimaryTests {
        @Test
        void test1() {
            System.out.println("第一条用例");
        }
    }

    @Nested
    @Order(2)
//    @DisplayName("a")
    class SecondaryTests {
        @Test
        void test2() {
            System.out.println("第二条用例");
        }
    }
}

使用默认配置指定顺序

  1. 新建配置文件(路径:src/main/resources/junit-platform.properties)
  2. 在配置文件中写入对应的配置信息
  3. 可以分别指定方法的默认配置和类的默认配置

#默认排序方式为随机排序
junit.jupiter.testmethod.order.default = org.junit.jupiter.api.MethodOrderer$Random
#默认排序方式为通过方法名排序
junit.jupiter.testmethod.order.default = org.junit.jupiter.api.MethodOrderer$MethodName
#默认排序方式为通过Order注解指定
junit.jupiter.testmethod.order.default = org.junit.jupiter.api.MethodOrderer$OrderAnnotation
#默认排序方式为通过DisplayName排序
junit.jupiter.testmethod.order.default = org.junit.jupiter.api.MethodOrderer$DisplayName

#默认排序方式为随机排序
junit.jupiter.testclass.order.default = org.junit.jupiter.api.ClassOrderer$Random
#默认排序方式为通过类名排序
junit.jupiter.testclass.order.default = org.junit.jupiter.api.ClassOrderer$ClassName
#默认排序方式为通过DisplayName排序
junit.jupiter.testclass.order.default = org.junit.jupiter.api.ClassOrderer$DisplayName
#默认排序方式为通过Order注解指定
junit.jupiter.testclass.order.default = org.junit.jupiter.api.ClassOrderer$OrderAnnotation

12,重复性测试 @RepeatedTest
使用场景:

  • 需要用例执行多次的场景
  • 接口的幂等性测试
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;

public class RepeatTest {
//    @Test                //如果添加 @Test 注解,则会多执行一次,使用重复测试注解的话,没必要用@Test
    @RepeatedTest(2)               // 注解内需要传递控制重复次数的参数
    void hogwarts(){
        System.out.println("霍格沃兹测试开发支付成功");
    }

    // value 表示要重复几次
    // displayName 对应执行用例的displayname,没有添加@DisplayName注解时,会默认调用对应的测试方法
    // currentRepetition 第几次重复
    // totalRepetitions 代表总共要重复的次数
    @RepeatedTest(value = 3, name = "{displayName} {currentRepetition} of {totalRepetitions}")
    @DisplayName("test001")
    void firstTest(){
        System.out.println("该用例为重复测试用例");
    }
}

13,标记测试用例@Tag
使用场景:

  • 通过 Tag 对用例分组:
    • 环境分组: 测试环境、预发布环境
    • 阶段分组: 冒烟用例
    • 版本分组: V1.1、V1.2

标记用例方法:

  • 设置标签
  • 根据标签执行
    • 结合 Maven 执行
    • 结合测试套件执行

自定义标签:

package tagDemo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

//定义标签
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Tag("hogwarts")
@Test
@interface PreprodTest {
}

设置标签:

package tagDemo;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


public class TagDemoTest {
    @Tag("grey")
    @Test
    void hogwarts(){
        System.out.println("灰度环境");
    }

    @Tag("test")
    @Test
    void hogwarts2(){
        System.out.println("测试环境");
    }
    @Tag("dev")
    @Test
    void hogwarts3(){
        System.out.println("开发环境");
    }
    @Tag("dev")
    @Tag("test")
    @Test
    void hogwarts4(){
        System.out.println("开发+测试环境");
    }

    //使用自定义标签,PreprodTest为定义的接口名称
    //使用mvn test -Dgroups="hogwarts" 执行该用例时,标签名应该使用接口定义的@Tag("hogwarts")这个标签名
    @PreprodTest
    void testCustomTag(){
        System.out.println("自定义的标签");

    }

}

Maven 结合 tag 构建-修改 pom 文件

需要导入的依赖配置:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.2</version>
            <configuration>
            <!-- 要执行的标签 -->
                <groups>test</groups>
            <!-- 不要执行的标签 -->
                <excludedGroups>dev</excludedGroups>
            </configuration>
        </plugin>
    </plugins>
</build>
  • groups 表示执行包含标签或者标签表达式的用例。
  • excludedGroups 表示不执行包含该标签或者标签表达式的用例。
  • 使用命令 mvn clean test 执行用例。

Maven 结合 tag 构建-使用命令行构建

  • 如果使用命令行的同时也配置了 pom 文件, pom 的配置优先级更高
# 执行 test 标签的用例
mvn clean test -Dgroups="test"
# 执行不含test 标签的用例
mvn clean test -DexcludedGroups="test"

命名规范

image

Tag表达式

表达式在pom文件使用:

           <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <!-- &amp; 在xml 中表示 & 与的关系 -->
                    <groups>test&amp;dev</groups>
                    <!-- 不要执行的标签 -->
<!--                    <excludedGroups>主流程方法</excludedGroups>-->
                </configuration>
                <version>2.22.2</version>
            </plugin>

表达式在命令行使用:

# 执行 没有test 标签的用例
mvn clean test -Dgroups="!test"
# 执行 dev 或 test 标签的用例
mvn clean test -Dgroups="dev|test"
# 执行既有 dev 也有 test 标签的用例
mvn clean test -Dgroups="dev&test"

14,禁用测试用例@Disable

  • 给用例添加禁用标识。
  • 被禁用的用例执行后会添加跳过的状态。
  • 可以禁用测试类、也可以禁用测试方法
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

//在类名添加Disabled注解
//注意:IDEA 不支持,maven 构建才支持跳过Disabled注解的测试类
//@Disabled
//@Disabled("Disabled until bug #99 has been resolved")             //也可以在注解里加上跳过该用例的原因说明
public class DisableDemoTest {

    @Test
    void test001() {
        System.out.println("测试用例1");
    }

    @Test
    void test002() {
        System.out.println("测试用例2");
    }

    //在方法名添加Disabled注解
    //IDEA和 maven 构建都支持跳过Disabled注解的测试方法
    @Disabled("Disabled until bug #42 has been resolved")
    @Test
    void testWillBeExecuted() {
        System.out.println("跳过的测试用例");
    }

}