基于xUnit的单元测试管理(Java语言)

读书笔记,更新到学完为止

什么是xUnit

  • xUnit是各种代码驱动测试框架的统称,这些框架可以测试软件的不同内容
  • 主要优点:提供了一个自动化测试的解决方案,不需要多次编写重复的测试代码,也不必记录测试的结果。
  • Java语言中典型的xUnit是JUnit和TestNG,Python语言中是UnitTest、PyTest。

xUnit的组成

  • 底层是xUnit的framwork,xUnit的类库,提供了对外的功能方法、工具类、api等
  • TestCase(具体的测试用例)去使用framwork
  • TestCase执行后会有TestResult
  • 使用TestSuite控制TestCase的组合
  • TestRunner执行器,负责执行case
  • TestListener过程监听,监听case成功失败以及数据结果,输出到结果报告中

xUnit用于测试的四要素

  • 测试目标(对象)
  • 测试集
  • 测试执行(过程)
  • 断言

JUnit和TestNG

  • 注解 suite>test>group>class>method


  • TestSuite
  • TestCase
  • TestRunner
  • TestResult
  • TestListener

常用断言

  • assertTrue 验证是或否
  • assertSame 验证是否匹配、相似、模糊匹配
  • assertEquals 验证是否相等

运行策略配置

  • JUnit

    • 运行器 Runwith(*Runner.class)
    • 套件 Suite.SuiteClass({*TestClass.class})
  • TestNG

    • 统一配置文件 Testng.xml
    • 套件

参数化和数据驱动

  • JUnit

    • @Parameterized.Parameters()
    • JUnit参数化是类级别的,即每循环一次都将执行这个类,包括@Before和@After
  • TestNG

    • @DataProvider(name="param")
    • @Test(dataprovider="param")
    • TestNG参数化是在测试级别的
  • 数据驱动能力

    • 第一级能力参数化
    • 第二级能力数据化
    • 第三级能力业务逻辑数据化
    • 第四级能力测试框架数据化

监听

  • ITestNGListener
  • IReporter

拓展性

  • JUnit
    • @Runwith(SpringRunner.class)
    • @SpringBootTest

与Maven结合的项目实践

  • 开源项目准备
    • 开源项目:https://github.com/leitianxiao/XunitDemo.git
    • 环境要求:Java、 maven、git、IDEA
    • 添加Maven依赖:https://mvnrepository.com
    • src/main/java 开发写代码的地方,开发可在每个类里写main方法自测
    • src/test/java 测试写代码的地方,对开发代码进行测试
  • 应用实战

    • 开发写了一个用户登陆的方法,也就是我们的测试对象
    //XunitDemo/src/main/java/DemoXunit/Login.java
    public class Login {
      public static boolean isLogin = false;
      public String userLogin(String name,String pwd){
          if(name == null || name.equals("") || pwd ==null || pwd.equals("")){
              System.out.println("用户名或密码为空");
              isLogin = false;
              return "用户名或密码不能为空";
    
          }else if (name == "admin" || name.equals("admin")){
              System.out.println("管理员");
              isLogin = true;
              return "欢迎管理员";
    
          }else{
              System.out.println("正常用户");
              isLogin = true;
              return "欢迎"+name;
          }
      }
    //开发自测
       public static void main(String[] args){
            Login login = new Login();
            login.userLogin("","");
      }
    }
    
    • 第一个测试用例
    //src/main/test/LoginTest.java
    public class LoginTest {
      @Test
      public void testLogin(){
          Login login = new Login();
          //执行用例
          String actual = login.userLogin("zhangsan","123456");
          //断言
          Assert.assertEquals(actual, "欢迎zhangsan");
        }
      }
    
    • 覆盖代码每个分支
    //src/main/test/TestXunit/LoginTest.java
    public class LoginTest {
     @Test
     public void testUserLogin1(){
         Login login = new Login();
         //执行用例
         String actual = login.userLogin("zhangsan","123456");
         //断言
         Assert.assertEquals(actual, "欢迎zhangsan");
       }
     @Test
     public void testUserLogin2(){
         Login login = new Login();
         String actual = login.userLogin("","");
         Assert.assertEquals(actual, "用户名或密码不能为空");
       }
     @Test
     public void testUserLogin3(){
         Login login = new Login();
         String actual = login.userLogin("admin","");
         Assert.assertEquals(actual, "用户名或密码不能为空");
       }
     @Test
     public void testUserLogin4(){
         Login login = new Login();
         String actual = login.userLogin("admin","12345");
         Assert.assertEquals(actual, "欢迎管理员");
       }
      }
    
    • 运行配置
      一个testng.xml只能配置一个,一个可以有多个,一个有多个,一个下有多个,一个下有多个,一个下有多个

      • 如何生成testng.xml文件
        方法一:plugins ---> 搜索插件creat testng xml ---> 安装 ---> 项目文件右键 ---> creat testng xml
        方法二:新建testng.xml文件,复制粘贴
        
        
        
            
            
        
        
      • testng.xml
      
      
      
          
             
                 
                     
                         
                             
                                 
                                     
                                     
                                     
                                     
                                 
                             
                         
                     
                 
             
          
      
      
    • 监听

      • 配置test-output
        Run --->Edit Configuarations --->Listeners ---> 勾选use default report

      • 查看report
        Run过testng.xml文件后,会在项目文件夹下生成test-output文件夹
        打开test-output/index.html,即TestNG reports
        test-output/old/index.html是旧版report

    • 参数化

      • 测试用例代码抽象化
      //src/main/test/TestXunit/LoginTest.java
      public class LoginTest {
      @Test
      public void testUserLogin(String name,String pwd,String expect){
          Login login = new Login();
          String actual = login.userLogin(name,pwd);
          Assert.assertEquals(actual, expect);
        }
      }
      
      • 参数化
        借助 @Parameters读取testng.xml中参数

        //src/main/test/TestXunit/LoginTest.java
        public class LoginTest {
            @Parameters({"name","pwd","expect"})
            @Test
            public void testUserLogin(String name,String pwd,String expect){
                Login login = new Login();
                String actual = login.userLogin(name,pwd);
                Assert.assertEquals(actual, expect);
            }
        }
        
        
        
        
        
            
                
                    
                        
                            
                                
                                    
                                        
                                        
                                        
                                    
                                
                            
                        
                    
                
            
            
        
    • 复杂测试数据使用@DataProvider注解传参

      • 创建一个专门存放测试数据的package:XunitDemo/src/test/java/LoginData

      • 在DataParams中新建一个存放测试数据的class:LoginParams.java,固定格式,每个花括号对应一条测试用例数据的name、pwd、expect

        //test/java/DataParams/LoginParams.java
        public class LoginParams {
           /**
           * 小技巧:打/** 然后command+回车,写注释,方便自己和别人查看代码
           *
           * 提供用户登陆测试数据
           * @return
           */
          @DataProvider
          public Object[][] getUsers(){
              return new Object[][]{
                    {"zhangsan","123456","欢迎zhangsan"},
                    {"","","用户名或密码不能为空"},
                    {"admin","","用户名或密码不能为空"},
                    {"admin","12345","欢迎管理员"}
                };
            }
        }
        
      • 测试数据关联到测试用例

        //src/main/test/TestXunit/LoginTest.java
        public class LoginTest {
          //dataProvider指定方法,dataProviderClass指定该方法所在的类
          @Test(dataProvider = "getUsers",dataProviderClass = LoginParams.class)
          public void testUserLogin(String name,String pwd,String expect){
              Login login = new Login();
              String actual = login.userLogin(name,pwd);
              Assert.assertEquals(actual, expect);
            }
        }
        
      • testng.xml运行配置

        
        
        
          
              
                  
                      
                          
                              
                                  
                                      
                                  
                              
                          
                      
                  
              
            
        
        

实战进阶(关联性测试)

  • 开发写的一个新方法
//src/main/java/DemoXunit/Shopping.java
public class Shopping {
    Login login = new Login();
    Products pro;

    /**
     * 通过ID查找商品价格
     *
     * @param proId 商品ID
     * @return 商品价格 ; -1 没有此商品;-2 未登录
     */
    public int getPrice(int proId) {
        if (login.isLogin == true) {
            if (proId <= 0) { //1
                return -1;
            } else {
                Products p = Products.getPro(proId);

                return p.getPrice();
            }
        } else {

            return -2;
        }
    }
      //自测
    public static void main(String[] args) {
        Shopping shopping = new Shopping();
        Login login = new Login();
        login.userLogin("", "123456");
        shopping.getPrice(1);
    }
}
  • 写了一个枚举类,假装是数据库
//src/main/java/DemoXunit/Products.java
//模拟数据库
public enum Products {
    //围巾的商品ID是1,商品名称是“围巾”,价格是200,库存是0
    WEIJIN(1,"围巾",200,0),
   //帽子的商品ID是2,商品名称是“帽子”,价格是200,库存是10
    MAOZI(2,"帽子",120,10),
    //手套的商品ID是3,商品名称是“手套”,价格是80,库存是1
    SHOUTAO(3,"手套",80,1);

    private int proId;  //商品ID
    private String proName;  //商品名称
    private int price;  //价格
    private int count;  //库存

    private Products(int proId, String proName, int price, int count){
        this.proId = proId;
        this.proName = proName;
        this.price = price;
        this.count = count;
    }

    /**
     * 通过商品ID 获取商品信息
     * @param proId
     * @return
     */
    public static Products getPro(int proId){

        for(Products product : Products.values()){
            if(product.getProId() == proId){
                return product;
            }
        }
        return null;
    }

  • 如何将登录关联到getPrice方法的测试

    • 方式一:通过配置执行顺序
      @BeforeClass,@AfterClass,@BeforeMethod,@AfterMethod...配合testng.xml

    • 方式二:写一个新的测试方法,包括了登录

    //src/test/java/TestXunit/ShoppingTest.java
    public class ShoppingTest {
        @Test(dataProvider ="getProPrice",dataProviderClass = ShoppingParams.class)
        public void testGetPrice(String name,String pwd,int proId,int expect){
            //登录
            Login login=new Login();
            login.userLogin(name,pwd);
            //查询商品价格
            Shopping shopping=new Shopping();
            int price=shopping.getPrice(proId);
            Assert.assertEquals(price,expect);
        }
    }
    

    参数化

    public class ShoppingParams {
      @DataProvider
      public Object[][] getProPrice(){
          return new Object[][]{
                  {"","",1,-2},
                  {"admin","",2,-2},
                  {"","",0,-2},
                  {"zhangsan","12345",1,200},
                  {"admin","12345",2,120},
                  {"lisi","123",3,80},
                  {"wang","123",0,-1}
    
          };
      }
    

    运行配置

    
    
    
        
            
                
                    
                        
                            
                                
                                    
                                
                            
                            
                                
                                    
                                
                            
                        
                    
                
            
        
    
    
  • TestNG与Surefire插件引入
    • 什么是Surefire插件

      • 它是一个用于mvn 生命周期的测试阶段的插件,可以通过一些参数设置方便的在testNG或junit下对测试阶段进行自定义。
      • testng是对测试用例管理,Surefire是对testng进行管理、对测试用例集(多个suite)的管理。
      • 在jenkin上做持续集成,命令mvn surefire:test,执行surefire中配置的testng.xml中的用例
    • pom文件添加依赖

       
          
              
                  org.apache.maven.plugins
                  maven-surefire-plugin
                  2.19.1
                  
                      
                          testng.xml
                      
                  
              
          
      
      

Allure2测试报告框架

  • JUnit style xml报告
  • mvn surefire插件的html报告
  • allure2 多语言测试报告
Allure
  • 官网:http://allure.qatools.ru
  • github:https://github.com/allure-framework/allure2/

1.Allure工作机制

  • 在测试框架中添加allure的依赖和配置
  • 执行测试用例
  • 生成allure-results
  • allure generate allure-result -o allure-report

2.Allure2安装

  • windows平台借助scoop安装 scoop install allure
  • macOS平台借助brew安装 brew install allure
  • 命令行输入allure --version测试是否安装成功

3.使用Allure2

在构建报告之前,您需要运行测试以获取一些基本的测试报告数据。通常,它可能是由几乎每个流行的测试框架生成的junit样式的xml报告。

  • 如使用surefire插件运行测试用例mvn surefire:test生成了target/surefire-reports
    使用命令:allure serve /home/path/to/project/target/surefire-reports/

  • 这是最简单的使用方式。

4.Allure报告结构
官网文档介绍:https://docs.qameta.io/allure/#_report_structure

5.Allure2进阶使用 (TestNG)
官方文档:https://docs.qameta.io/allure/#_testng

  • pom.xml文件添加依赖:
    其中LAST_VERSION表示最新版本号,查阅文档即可。
    
        1.8.10
    
    
    
        
            io.qameta.allure
            allure-testng
            LAST_VERSION
            test
        
    
    
    
        
            
                org.apache.maven.plugins
                maven-surefire-plugin
                2.20
                
                    
                      -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                    
                
                
                    
                        org.aspectj
                        aspectjweaver
                        ${aspectj.version}
                    
                
            
        
    
    
  • 运行构建mvn clean test,Allure结果将出现在target/allure-results文件夹中。
  • 生成html报告并在Web浏览器中自动打开它:allure serve target/allure-results

6.Allure的特性
官方文档:

  • Description:通过@TestDescription给测试方法添加人性化的命名

  • @Description:通过@Description给每个测试方法添加详细说明

  • @Link:将测试链接到某些资源,如测试管理系统

  • @Severity:用于按严重性确定测试方法的优先级

  • @Steps:步骤是构成测试场景的任何操作。使用@Step注释来注释相应的方法,每个步骤都有一个名称。

  • @Attachment:附件,使用@Attachment注释的方法,该方法返回String或byte [],更方便的是使用Allure辅助方法Allure.addAttachment()

    public class LoginTest {
      @Description("购物系统用户登录单元测试")
      @Issue("123")
      @Link("https://github.com/allure-framework/allure2/")
      @Test(dataProvider = "getUsers",dataProviderClass = LoginParams.class,description = "用户登录测试")
      @Step("步骤1")
      @Severity(SeverityLevel.NORMAL)
      public void testUserLogin(String name,String pwd,String expect){
          Login login = new Login();
          String actual = login.userLogin(name,pwd);
          //使用Allure.addAttachment
          try {
              Allure.addAttachment("demo pic","image/jpeg",new FileInputStream("/Users/leitianxiao/Downloads/02.jpeg"),".jpeg");
          } catch (FileNotFoundException e) {
              e.printStackTrace();
          }
          Assert.assertEquals(actual, expect);
      }
    }
    

7.生成静态报告

  • 使用allure serve target/allure-results生成的是临时报告
  • 命令allure generate -c allure-results,会在项目文件夹下生成新文件夹allure-report,打开allure-report/widgets/index.html,即静态测试报告

遗留问题待更新

  1. 还有什么方法获取数据源,比如需要2万条测试数据?
    csv文件读取、读取数据库、yaml文件读取

你可能感兴趣的:(基于xUnit的单元测试管理(Java语言))