IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> Junit5 单元测试框架的使用 -> 正文阅读

[开发测试]Junit5 单元测试框架的使用

Junit5 简单使用总结

作为一款测试框架,一般我们需要从以下几个方面去考虑

  • TestCase : 测试用例的管理
  • Assertions : 用例断言的管理
  • Test Execution: 测试执行,以何种顺序执行
  • Test Fixtures : 测试装置,测试用例运行的前后动作,用来管理测试用例的执行
  • Test Suites: 测试套,控制用例批量运行
  • Test Runner: 测试用例的运行器
  • Test Result Report: 测试报告

Junit5 架构

junit5 大体由3个模块组成

  • Junit platform 其主要作用在JVM 上启动测试框架,支持通过命令行Gradle maven 和Api 来运行平台
  • Junit Jupiter :核心功能 用于编写测试用例
  • Junit vintage : 承载兼容老版本的用例运行

工程环境搭建 参考官网在pom.xml 文件中引入依赖

 <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

   <dependencies>
        <!-- Only needed to run tests in a version of IntelliJ IDEA that bundles older versions -->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.junit</groupId>
                <artifactId>junit-bom</artifactId>
                <version>5.8.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <!-- Maven 运行的依赖插件 -->
        <plugins>

                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.2</version>
                </plugin>

        </plugins>
    </build>

用例写作之常用注解

@Test标记在方法上,表示测试用例
@BeforeEach表示被注解的方法,会在每个测试用例执行之前运行,@BeforeEach 注解支持继承
@AfterEach表示被注解的方法,会在每个测试用例执行之后运行,@AfterEach 注解支持继承
@BeforeAll表示在所有的测试方法运行之前执行, @BeforeAll 注解可以被继承
@AfterAll表示所有的测试方法运行之后执行 @BeforeAll 注解可以被继承
@DisplayName声明测试类或者测试方法显示的名称,此注解不会被继承
@Tag用于类或者方法上,做标签,后续可以根据标签来选择用例的执行,此注解用于类上可以被继承,用于方法上不可以被继承
@Disabled用于类或者方法上 ,禁用测试类
@Nested嵌套类的使用,但必须要求内部类是非静态内部类
@ParameterizedTest参数化
@RepeatedTest用例重复执行,可以用来测试并发场景
@order指定用例的执行顺序,传入数字即可
@TestMethodOrder指定用例以何种顺序执行,传入指定的MethodOrder 就可以自定义实现顺序https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-execution-order-methods
@DisplayName("测试计算器")
@TestMethodOrder(MethodOrderer.MethodName.class)
public class CalculatorTest {


    @BeforeAll
    public static void beforeAll(){
        System.out.println("Calculator test Before All");
    }


    @BeforeEach
    public void beforeEach(){
        System.out.println("Calculator test Before Each");
    }


    @Test
    @DisplayName("测试加法正常运算")
    public void testAdd(){
        int result = Calculator.add(2,4);
        System.out.println(result);
        Assertions.assertEquals(result,6);
    }

    @Test
    @DisplayName("测试减法运算")
   @Disabled
    public void testSubtraction(){
        int result = Calculator.subtraction(10,6);
        System.out.println("减法运算结果是:" + result);
        Assertions.assertEquals(result,4);
    }

    @Test
    @DisplayName("测试乘法运算")
    @Order(2)
    public void testMultiplication(){
        int result = Calculator.multiplication(2,4);

        System.out.println("乘法运算结果是:" + result);
        Assertions.assertEquals(result,8);
    }

    @Test
    @DisplayName("测试除法运算")
    @Order(3)
    public void testDivision(){
        int result = Calculator.division(10,3);
        System.out.println("除法运算结果是:" + result);
        Assertions.assertEquals(result,3);
    }

    @AfterEach
    public void afterEach(){
        System.out.println("Calculator test After each");
    }

    @AfterAll
    public static void afterAll(){
        System.out.println("Calculator test After All");
    }
}

@Nested 嵌套测试

public class NestedDemoTest {


    @Test
    @DisplayName("外层测试")
    public void testOuter(){
        System.out.println("outer....");
    }

    @DisplayName("内层测试")
    @Nested
    class Inner01{
        @Test
        @DisplayName("inner01 test")
        public void test(){
            System.out.println("inner01");
        }

        @Nested
        @DisplayName("inner01 嵌套")
        class InInner{
            @Test
            public void test(){
                System.out.println("inner01 嵌套inner 01");
            }
        }
    }

    @Nested
    @DisplayName("inner02")
    class Inner02{
        @Test
        @DisplayName("inner02 test")
        public void test(){
            System.out.println("inner02");
        }
    }
}

@Nested 用例,然后再执行第二层嵌套的用例: 外层->倒叙嵌套->第二层嵌套

junit5 断言体系

  • Assertions.assertEquals() 判断两个值是否相等
  • Assertions.assertNotEquals() 判断两个值是否不相等
  • Assertions.assertNull() 判断是否为空
  • Assertions.asserNotNull() 判断是否不为空
  • Assertions.assertSame() 判断两个对象的内存地址引用值是否相同
  • Assertions.assertNotSame() 判断两个对象的内存地址引用值是否不相等
  • assertTrue(Condition condition) 断言值为true
  • asserFalse(Condition condition) 断言值为false

Junit5 软断言的支持,软断言是指第一步校验不过,还可以继续向下校验

Assertions.assertAll(Executable… excutable) Executable 是一个函数式接口,可以通过lambda 表达式进行传值, …代表可变参数列表

 Assertions.assertAll(() -> Assertions.assertEquals(result,5));

多线程并发测试

在resources 目录下新建junit 配置文件 junit-platform.properties https://junit.org/junit5/docs/current/user-guide/#writing-tests-parallel-execution

# 是否允许并行测试 true/false
junit.jupiter.execution.parallel.enabled=true
# 是否允许测试方法并行执行,same_thread 同一线程执行, concurrent 多线程并发执行
junit.jupiter.execution.parallel.mode.default=concurrent
# 是否允许测试类之间的并发执行
junit.jupiter.execution.parallel.mode.classes.default = same_thread
# 配置并行策略fixed 或者dynamic 使用fixed 需要自行配置多线程并发执行数
junit.jupiter.execution.parallel.config.strategy = fixed
junit.jupiter.execution.parallel.config.fixed.parallelism = 2

在测试用例上用@RepeatTest 注解来实现并发允许

@RepeatedTest(10)
    public void testCount() throws InterruptedException {
        int result = Calculator.count(1);
        System.out.println(result);
    }

测试套件的运行以及指定测试类

参考: https://junit.org/junit5/docs/current/user-guide/#testkit-engine

在pom.xml 文件中添加依赖
 <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite-api</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite-engine</artifactId>
            <scope>test</scope>
        </dependency>
        
 
 在测试类中添加@Suit 注解创建测试套
 import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
import org.junit.platform.suite.api.SuiteDisplayName;



@Suite
@SuiteDisplayName("批量测试套")
@IncludeClassNamePatterns("*Test")
@IncludeTags({})
@SelectClasses({})
@ExcludeClassNamePatterns("")
@ExcludePackages({})
@ExcludeTags({})
@SelectPackages({"com.huawei.test"})
public class SuitDemo {
}
@Suite创建测试套件
@SuiteDisplayName测试套命名
@SelectClass()选择加入测试套的用例
@SelectPackage()选择包下面的所有用例
@IncludeClassNamePatterns("*Test")选择运行类名包含Test
@ExcludeClassNamePatterns("")排除类名符合某种规则
@ExcludePackages({})排除选择的包
@ExcludeTags({})排除被Tag 标记的测试用例

命令行 利用mvn test 和Maven Surefire plugin 插件做测试用例的执行管理

  • mvn test 执行全量的用例
  • mvn -Dtest=${TestClass} test 指定测试用例运行 如 mvn -DTest =SuitDemo test
  • mvn -Dtest= T e s t C l a s s 1 , {TestClass1}, TestClass1,{TestClass2} test 指定多个测试类运行
  • mvn -Dtest=${*TestClass} 通过匹配的方式指定测试类的运行
  • mvn -Dtest=KaTeX parse error: Expected 'EOF', got '#' at position 12: {TestClass}#?{TestMethod} 指定测试方法运行

用例参数化

public class ParamDemoTest {


    @ParameterizedTest
    @ValueSource(ints={1,3})
    public void testCount(int x) throws InterruptedException {
        int result = Calculator.count(x);
        System.out.println(result);
    }

    @ParameterizedTest
    @CsvSource(value = {"zhangsan,22,男","lisi,33,女"})
    public void testCsv(String arg1 ,String arg2,String arg3){

        System.out.println("arg1:" + arg1);

        System.out.println("arg2:" + arg2);
        System.out.println("arg3:" + arg3);
    }

    @ParameterizedTest
    @CsvFileSource(resources = "/data/user.csv")
    public void testCsvFile(String arg1 ,String arg2){

        System.out.println("arg1:" + arg1);

        System.out.println("arg2:" + arg2);
    }

    /**
     * @MethodSource 指定数据源的来源方法,方法的返回值可以时Array List Stream 等可迭代的对象
     */
    @ParameterizedTest
    @MethodSource(value = {"getData"})
    public void testMethod(String arg){
        System.out.println(arg);
    }

    @ParameterizedTest
    @MethodSource(value = {"getMap"})
    public void testMethod1(Map.Entry entry){
        System.out.println(entry.getKey());
        System.out.println(entry.getValue());
    }


    public void testGetYaml(){

    }

    static Iterator<Map.Entry<String, String>> getMap(){
        HashMap<String,String> map = new HashMap<>();

        map.put("name","zhangsan");
        map.put("sex","男");
        return map.entrySet().iterator();
    }

    static Stream<String> getData(){
        return Stream.of("zhangsan","lisi");

    }


    @Test
    public void testYaml() throws IOException {
        ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());

//        TypeReference typeReference = new TypeReference() {
//        }

        TypeReference typeReference = new TypeReference<List<YamlData>>() {

        };

        List<YamlData> yamlData = objectMapper.readValue(this.getClass().getResourceAsStream("/data/testdata.yaml"),typeReference);

        yamlData.forEach((data) ->{
            System.out.println(data.username + data.age);
        });

    }
}

利用Jackson + yaml 实现参数化步骤:

参考链接:https://www.baeldung.com/jackson-yaml

  • pom.xml 文件中添加Jackson 的依赖包

     <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.8</version>
            </dependency>
    
  • 添加jackson 支持yaml的依赖包

    <dependency>
                <groupId>com.fasterxml.jackson.dataformat</groupId>
                <artifactId>jackson-dataformat-yaml</artifactId>
                <version>2.9.8</version>
            </dependency>
    
  • 编写yaml

    -
      username: zhangsan
      age: 20
      computers:
        - brand: 华为
          price: 19999
        - brand: 小米
          price: 9999.9
      action:
        eat: 大鱼大肉
        sleep: 10小时
      map:
        id: 001
        step: 向后走
    
    -
      username: lisi
      age: 30
      computers:
        - brand: mac
          price: 29999
      action:
        eat: 青菜萝卜
        sleep: 10小时
      map:
        id: 002
        step: 向前走
        
        
    //yaml 以缩进代表层级关系 不允许tab 以两个空格代表缩进
    
  • 定义对应格式的实体类,注意如果属性是私有属性提供响应get/set 方法

    @JsonIgnoreProperties(ignoreUnknown = true)
    public class YamlData {
    
        private String username;
    
        private int age;
    
        private List<Computer> computers;
    
        private Action action;
    
        private HashMap<String,String> map;
        
        //get/set 方法省略....
        
    }
    
  • 编写相应的测试类

     @Test
        public void testYaml() throws IOException {
            ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
    
    //        TypeReference typeReference = new TypeReference() {
    //        }
    
            TypeReference typeReference = new TypeReference<List<YamlData>>() {
    
            };
    
            List<YamlData> yamlData = objectMapper.readValue(this.getClass().getResourceAsStream("/data/testdata.yaml"),typeReference);
    
            yamlData.forEach((data) ->{
                System.out.println(data.username + data.age);
            });
    
        }
    }
    

Junit + allure 测试报告展示

allure 环境准备

官方参考连接:https://github.com/allure-examples

参考连接:https://blog.csdn.net/huggh/article/details/90905845

Allure 安装下载地址:

https://repo1.maven.org/maven2/io/qameta/allure/allure-commandline/

  • 下载完成之后解压,加bin目录加载到环境变量path中
  • 本地电脑需要具备java 环境

Allure 命令

Allure --help 帮助

Allure --version 查看版本信息

Allure serve 生成在线版本的测试

allure generate -o 输出目录

@Feature模块名称
@Story用例名称
@DisplyaName用例标题
@Issue缺陷地址
@Step操作步骤
@Severity用例等级,blocker、critical、normal、minor、trivial
@link定义连接
Allure.addAttachment附件
  <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>

        <aspectj.version>1.9.1</aspectj.version>
        <allure.version>2.13.6</allure.version>
        <junit5.version>5.7.0</junit5.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit5.version}</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit5.version}</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>${junit5.version}</version>
        </dependency>

        <dependency>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-junit5</artifactId>
            <version>${allure.version}</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.30</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
                <configuration>
                    <testFailureIgnore>false</testFailureIgnore>
                    <argLine>
                        -Dfile.encoding=UTF-8
                        -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                    </argLine>
                    <systemPropertyVariables>
                        <allure.results.directory>${project.build.directory}/allure-results</allure.results.directory>

                        <junit.jupiter.extensions.autodetection.enabled>true</junit.jupiter.extensions.autodetection.enabled>
                        <junit.jupiter.execution.parallel.enabled>true</junit.jupiter.execution.parallel.enabled>
                        <junit.jupiter.execution.parallel.config.strategy>dynamic</junit.jupiter.execution.parallel.config.strategy>
                    </systemPropertyVariables>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.junit.platform</groupId>
                        <artifactId>junit-platform-surefire-provider</artifactId>
                        <version>1.3.2</version>
                    </dependency>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjweaver</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>

                </dependencies>
            </plugin>

            <plugin>
                <groupId>io.qameta.allure</groupId>
                <artifactId>allure-maven</artifactId>
                <version>2.10.0</version>
                <configuration>
                    <reportVersion>${allure.version}</reportVersion>
                    <resultsDirectory>${project.build.directory}/allure-results</resultsDirectory>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

        </plugins>
    </build>

@Attachment
       @Step("进行截图")
       public byte[] makeScreenShot() {
            return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
       }
       
    @Attachment(value = "pic", type = "image/jpg",fileExtension = "jpg")
    public byte[] makeScreenShot() throws IOException {
        InputStream resourceAsStream = this.getClass().getResourceAsStream("/image/1.jpg");
        byte[] bytes = new byte[1024 * 1024];
        return Arrays.copyOfRange(bytes,0,resourceAsStream.read(bytes));

    }

    @Attachment
    public String makeAttach() {
        return "yeah, 2 is 2";
    }
    
    
    
    //
   Allure.addAttachment("demo picture","image/jpg",this.getClass().getResourceAsStream("/image/1.jpg"),"jpg");
  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2022-01-25 10:52:56  更:2022-01-25 10:53:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 4:18:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码