读书笔记,更新到学完为止
什么是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
- 如何生成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:通过
@Test
的Description
给测试方法添加人性化的命名@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
,即静态测试报告
遗留问题待更新
- 还有什么方法获取数据源,比如需要2万条测试数据?
csv文件读取、读取数据库、yaml文件读取