讀書筆記,更新到學完為止
什么是xUnit
- xUnit是各種代碼驅動測試框架的統(tǒng)稱,這些框架可以測試軟件的不同內(nèi)容
- 主要優(yōu)點:提供了一個自動化測試的解決方案,不需要多次編寫重復的測試代碼,也不必記錄測試的結果。
- Java語言中典型的xUnit是JUnit和TestNG蝌麸,Python語言中是UnitTest、PyTest艾疟。
xUnit的組成
- 底層是xUnit的framwork来吩,xUnit的類庫敢辩,提供了對外的功能方法、工具類弟疆、api等
- TestCase(具體的測試用例)去使用framwork
- TestCase執(zhí)行后會有TestResult
- 使用TestSuite控制TestCase的組合
- TestRunner執(zhí)行器戚长,負責執(zhí)行case
- TestListener過程監(jiān)聽,監(jiān)聽case成功失敗以及數(shù)據(jù)結果怠苔,輸出到結果報告中
xUnit用于測試的四要素
- 測試目標(對象)
- 測試集
- 測試執(zhí)行(過程)
- 斷言
JUnit和TestNG
-
注解 suite>test>group>class>method
- TestSuite
- TestCase
- TestRunner
- TestResult
- TestListener
常用斷言
- assertTrue 驗證是或否
- assertSame 驗證是否匹配同廉、相似、模糊匹配
- assertEquals 驗證是否相等
運行策略配置
-
JUnit
- 運行器 Runwith(*Runner.class)
- 套件 Suite.SuiteClass({*TestClass.class})
-
TestNG
- 統(tǒng)一配置文件 Testng.xml
- 套件 <suite><test></test></suite>
參數(shù)化和數(shù)據(jù)驅動
-
JUnit
- @Parameterized.Parameters()
- JUnit參數(shù)化是類級別的柑司,即每循環(huán)一次都將執(zhí)行這個類迫肖,包括@Before和@After
-
TestNG
- <Parameter name="" value="">
- @DataProvider(name="param")
- @Test(dataprovider="param")
- TestNG參數(shù)化是在測試級別的
-
數(shù)據(jù)驅動能力
- 第一級能力參數(shù)化
- 第二級能力數(shù)據(jù)化
- 第三級能力業(yè)務邏輯數(shù)據(jù)化
- 第四級能力測試框架數(shù)據(jù)化
監(jiān)聽
- ITestNGListener
- IReporter
拓展性
- JUnit
- @Runwith(SpringRunner.class)
- @SpringBootTest
與Maven結合的項目實踐
- 開源項目準備
- 開源項目:https://github.com/leitianxiao/XunitDemo.git
- 環(huán)境要求:Java、 maven攒驰、git蟆湖、IDEA
- 添加Maven依賴:https://mvnrepository.com
-
src/main/java
開發(fā)寫代碼的地方,開發(fā)可在每個類里寫main方法自測 -
src/test/java
測試寫代碼的地方玻粪,對開發(fā)代碼進行測試
-
應用實戰(zhàn)
- 開發(fā)寫了一個用戶登陸的方法隅津,也就是我們的測試對象
//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; } } //開發(fā)自測 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(); //執(zhí)行用例 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(); //執(zhí)行用例 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只能配置一個<suite>,一個<suite>可以有多個<test>,一個<test>有多個<group>,一個<group>下有多個<class>,一個<class>下有多個<methods>劲室,一個<methods>下有多個<include>或<exclude>- 如何生成testng.xml文件
方法一:plugins ---> 搜索插件creat testng xml ---> 安裝 ---> 項目文件右鍵 ---> creat testng xml
方法二:新建testng.xml文件饥瓷,復制粘貼<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="All Test Suite"> <test verbose="2" preserve-order="true" name="/Users/leitianxiao/Documents/xuint"> </test> </suite>
- testng.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="All Test Suite"> <test verbose="1" preserve-order="true" name="/Users/leitianxiao/Documents/XunitDemo"> <groups> <dependencies> <group name="group1" depends-on=""> <classes> <class name="LoginTest"> <methods> <include name="testUserLogin1"></include> <include name="testUserLogin2"></include> <include name="testUserLogin3"></include> <include name="testUserLogin4"></include> </methods> </class> </classes> </group> </dependencies> </groups> </test> </suite>
- 如何生成testng.xml文件
-
監(jiān)聽
配置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
-
參數(shù)化
- 測試用例代碼抽象化
//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); } }
-
參數(shù)化
借助 @Parameters讀取testng.xml中參數(shù)//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); } }
<!--testng.xml--> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="All Test Suite"> <test verbose="2" preserve-order="true" name="/Users/leitianxiao/Documents/XunitDemo"> <groups> <dependencies> <group name="group1" depends-on=""> <classes> <class name="TestXunit.LoginTest"> <methods> <parameter name="name" value="zhangsan"></parameter> <parameter name="pwd" value="123456"></parameter> <parameter name="expect" value="歡迎zhangsan"></parameter> </methods> </class> </classes> </group> </dependencies> </groups> </test> </suite>
-
復雜測試數(shù)據(jù)使用@DataProvider注解傳參
創(chuàng)建一個專門存放測試數(shù)據(jù)的package:
XunitDemo/src/test/java/LoginData
-
在DataParams中新建一個存放測試數(shù)據(jù)的class:
LoginParams.java
,固定格式晦鞋,每個花括號對應一條測試用例數(shù)據(jù)的name蹲缠、pwd、expect//test/java/DataParams/LoginParams.java public class LoginParams { /** * 小技巧:打/** 然后command+回車悠垛,寫注釋线定,方便自己和別人查看代碼 * * 提供用戶登陸測試數(shù)據(jù) * @return */ @DataProvider public Object[][] getUsers(){ return new Object[][]{ {"zhangsan","123456","歡迎zhangsan"}, {"","","用戶名或密碼不能為空"}, {"admin","","用戶名或密碼不能為空"}, {"admin","12345","歡迎管理員"} }; } }
-
測試數(shù)據(jù)關聯(lián)到測試用例
//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運行配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="All Test Suite"> <test verbose="2" preserve-order="true" name="/Users/leitianxiao/Documents/XunitDemo"> <groups> <dependencies> <group name="group1" depends-on=""> <classes> <class name="LoginTest"> <methods> <include name="testUserLogin"></include> </methods> </class> </classes> </group> </dependencies> </groups> </test> </suite>
實戰(zhàn)進階(關聯(lián)性測試)
- 開發(fā)寫的一個新方法
//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);
}
}
- 寫了一個枚舉類,假裝是數(shù)據(jù)庫
//src/main/java/DemoXunit/Products.java
//模擬數(shù)據(jù)庫
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;
}
-
如何將登錄關聯(lián)到getPrice方法的測試
方式一:通過配置執(zhí)行順序
@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); } }
參數(shù)化
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} }; }
運行配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="All Test Suite"> <test verbose="2" preserve-order="true" name="/Users/leitianxiao/Documents/XunitDemo"> <groups> <dependencies> <group name="group1" depends-on=""> <classes> <class name="TestXunit.LoginTest"> <methods> <include name="testUserLogin"></include> </methods> </class> <class name="TestXunit.ShoppingTest"> <methods> <include name="testGetPrice"></include> </methods> </class> </classes> </group> </dependencies> </groups> </test> </suite>
- TestNG與Surefire插件引入
-
什么是Surefire插件
- 它是一個用于mvn 生命周期的測試階段的插件,可以通過一些參數(shù)設置方便的在testNG或junit下對測試階段進行自定義岸浑。
- testng是對測試用例管理搏存,Surefire是對testng進行管理、對測試用例集(多個suite)的管理矢洲。
- 在jenkin上做持續(xù)集成璧眠,命令
mvn surefire:test
,執(zhí)行surefire中配置的testng.xml中的用例
-
pom文件添加依賴
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19.1</version> <configuration> <suiteXmlFiles> <suiteXmlFile>testng.xml</suiteXmlFile> </suiteXmlFiles> </configuration> </plugin> </plugins> </build>
-
Allure2測試報告框架
- JUnit style xml報告
- mvn surefire插件的html報告
- allure2 多語言測試報告
Allure
- 官網(wǎng):http://allure.qatools.ru
- github:https://github.com/allure-framework/allure2/
1.Allure工作機制
- 在測試框架中添加allure的依賴和配置
- 執(zhí)行測試用例
- 生成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
在構建報告之前兵钮,您需要運行測試以獲取一些基本的測試報告數(shù)據(jù)蛆橡。通常,它可能是由幾乎每個流行的測試框架生成的junit樣式的xml報告掘譬。
如使用surefire插件運行測試用例
mvn surefire:test
生成了target/surefire-reports
使用命令:allure serve /home/path/to/project/target/surefire-reports/
這是最簡單的使用方式泰演。
4.Allure報告結構
官網(wǎng)文檔介紹:https://docs.qameta.io/allure/#_report_structure
5.Allure2進階使用 (TestNG)
官方文檔:https://docs.qameta.io/allure/#_testng
- pom.xml文件添加依賴:
其中LAST_VERSION
表示最新版本號,查閱文檔即可葱轩。<properties> <aspectj.version>1.8.10</aspectj.version> </properties> <dependencies> <dependency> <groupId>io.qameta.allure</groupId> <artifactId>allure-testng</artifactId> <version>LAST_VERSION</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.20</version> <configuration> <argLine> -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" </argLine> </configuration> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> </dependencies> </plugin> </plugins> </build>
- 運行構建
mvn clean test
,Allure結果將出現(xiàn)在target/allure-results
文件夾中睦焕。 - 生成html報告并在Web瀏覽器中自動打開它:
allure serve target/allure-results
6.Allure的特性
官方文檔:
Description:通過
@Test
的Description
給測試方法添加人性化的命名@Description:通過
@Description
給每個測試方法添加詳細說明@Link:將測試鏈接到某些資源,如測試管理系統(tǒng)
@Severity:用于按嚴重性確定測試方法的優(yōu)先級
@Steps:步驟是構成測試場景的任何操作靴拱。使用@Step注釋來注釋相應的方法垃喊,每個步驟都有一個名稱。
-
@Attachment:附件袜炕,使用@Attachment注釋的方法本谜,該方法返回String或byte [],更方便的是使用Allure輔助方法
Allure.addAttachment()
public class LoginTest { @Description("購物系統(tǒng)用戶登錄單元測試") @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.生成靜態(tài)報告
- 使用
allure serve target/allure-results
生成的是臨時報告 - 命令
allure generate -c allure-results
偎窘,會在項目文件夾下生成新文件夾allure-report
乌助,打開allure-report/widgets/index.html
,即靜態(tài)測試報告
遺留問題待更新
- 還有什么方法獲取數(shù)據(jù)源陌知,比如需要2萬條測試數(shù)據(jù)他托?
csv文件讀取、讀取數(shù)據(jù)庫仆葡、yaml文件讀取