如何利用 xUnit 框架對測試用例進行維護?


本文為霍格沃茲測試學院優秀學員 Junit 學習筆記。測試開發技能進階。

1、xUnit 是什麼

先看 Wikipedia 上的解釋:

如何利用 xUnit 框架對測試用例進行維護?

xUnit 是一系列測試框架的統稱,最開始來源於一個叫做 Smalltalk 的 SUnit 框架,現在各種面向對象的語言,如 Java、Python 的鼻祖就是 Smalltalk,後來這些語言都藉助了 Sunit 框架的理念,有很多通用的規範和特徵,也就統稱為 xUnit。

1.1 xUnit 框架體系
  • Java : JUnit、TestNG
  • Python : UnitTest、PyTest
1.2 xUnit 的共同特徵
  • Test Runner :測試的運行器
  • Test Case :測試用例
  • Test Fixtures : 測試夾具 / 治具,用來管理測試用例的執行
  • Test Suites :測試套件,用來編排測試用例
  • Test Execution:測試執行,以何種順序執行
  • Test Result Formatter:測試結果,具備相同的格式,可被整合
  • Assertions:斷言

2、從 Junit4 開啟 xUnit 框架之旅

2.1 為何從 Junit4 開始
  • Junit4 仍然是 99% 的研發工程師的首選框架,方便測試工程師與研發工程師交流(拉關係~~);
  • TestNG 的使用多用於測試工程師;
  • Junit5 還未大規模普及(最推薦的框架,成熟、好用、研發測試通用);
  • 很多框架基於 Junit4 定製;
2.2 測試用例的核心元素
  • 測試用例的名字:特性方法名
  • 測試用例描述與標籤:註解
  • 測試用例的容器:類或者套件
  • 測試過程
    • 單元測試
    • Web 自動化測試 Selenium
    • App 自動化測試 Appium
    • 接口自動化測試 RestAssured
  • 測試斷言
2.3 基本 demo 運行

1)創建 maven 工程 XUnit,pom.xml 中添加 Junit 依賴;

<code>
    junit
    junit
    4.12
    test
/<code>

2)src/test/java 下創建測試類 Junit4DemoTest

注意

測試類要以 Test 開頭或者結尾

maven auto-import

src/main/java 存放應用實現代碼

src/test/java 存放單元測試

單元測試的原則之一:用例可以獨立運行

基本測試 demo 運行:

如何利用 xUnit 框架對測試用例進行維護?

運行結果:

如何利用 xUnit 框架對測試用例進行維護?

2.4 用例間的執行順序

Junit4:

  • Default 取決於反射方法獲得的列表,順序固定(不保險)
  • @FixMethodOrder(MethodSorters.JVM) 順序可能變化
  • @FixMethodOrder(MethodSorters.NAME_ASCENDING) 按照名字 ASCII 順序(穩定常用,建議使用)

TestNG、Junit5:

  • 可以通過註解設置順序 Order

順序演示

如何利用 xUnit 框架對測試用例進行維護?

運行結果:

如何利用 xUnit 框架對測試用例進行維護?

2.5 測試套件的執行順序支持
如何利用 xUnit 框架對測試用例進行維護?

  • Junit4:
    • @BeforeClass、@AfterClass
    • @Before、@After
  • TestNG:
    • @BeforeClass
    • @BeforeMethod
    • BeforeGroup、@BeforeSuite
  • Junit5:
    • @BeforeClass
    • @BeforeEach


實操演示 1

  • 在用例執行前後增加 @Before 和 @After:
如何利用 xUnit 框架對測試用例進行維護?

運行結果:

如何利用 xUnit 框架對測試用例進行維護?

實操演示 2

  • 再增加 @BeforeClass 和 @AfterClass
如何利用 xUnit 框架對測試用例進行維護?

運行結果:

如何利用 xUnit 框架對測試用例進行維護?

2.5 用例管理的實際應用舉例——App 自動化測試用例管理
  • 基類的 @BeforeClass:
    • 配置讀取、配置 Capability、初始化 driver、安裝 App,PageObject 初始化
  • 集成的子類執行流程
    • @Before:啟動並進入特定界面
    • @Test:測試用例執行
    • @After:回退到入口
    • @BeforeClass:進圖特定的 tab 子功能頁面
    • @AfterClass:關閉 app
  • 基類的 @AfterClass
    • driver.quit
2.6 繼承關係下的測試流程

流程順序:

  • 父類 @BeforeClass
  • 子類 @BeforeClass
  • 父類 @Before
  • 子類 @Before
  • 子類 @Test
  • 父類 @Test
  • 子類 @After
  • 父類 @After
  • 子類 @AfterClass
  • 父類 @AfterClass

實操演示 1

  • 現在創建一個子類 Junit4DemoChildrenTest,繼承 Junit4DemoTest,然後實現和父類一樣的方法並運行子類:
如何利用 xUnit 框架對測試用例進行維護?

運行結果:

如何利用 xUnit 框架對測試用例進行維護?

從運行結果中我們可以看到,子類會將與父類中一樣的方法進行覆蓋,只執行子類中的方法

實操演示 2

  • 現在將子類中的方法名進行修改,使其與父類方法名不同,再運行子類:
如何利用 xUnit 框架對測試用例進行維護?

運行結果:

<code>我是 @BeforeClass,我是第一步
我是 Children@BeforeClass,我是第一步

我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
Children testDemoB
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這



我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
Children testDemoA
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這



java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:86)
    at org.junit.Assert.assertTrue(Assert.java:41)
    at org.junit.Assert.assertTrue(Assert.java:52)
    ...
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)



我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
Children testDemoC
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這



我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
testDemoA
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這



java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:86)
    at org.junit.Assert.assertTrue(Assert.java:41)
    at org.junit.Assert.assertTrue(Assert.java:52)
    ...
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)



我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
testDemoB
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這



我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
testDemoC
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這

我是 Children@AfterClass,我是最後一步
我是 @AfterClass,我是最後一步/<code>
2.7 測試套件
  • RunWith
  • SuiteClasses
  • class

實操演示

  • 新建一個子類 Junit4DemoChildren2Test,繼承 Junit4DemoTest
如何利用 xUnit 框架對測試用例進行維護?

  • 再建一個測試類 SuitesTest, 寫上註解 @RunWith(Suite.class), 表明這是一個測試套件,是多個測試類的一個集合,一個容器;
  • 然後利用註解 @Suite.SuiteClasses 來設置測試類集合,設置測試類執行的順序
如何利用 xUnit 框架對測試用例進行維護?


運行結果:

如何利用 xUnit 框架對測試用例進行維護?

<code>我是 @Before,用例執行前先到我這
我是 Children2@Before,用例執行前先到我這
Children2 testDemoC
我是 Children2@After, 用例執行後到我這
我是 @After, 用例執行後到我這


我是 @Before,用例執行前先到我這
我是 Children2@Before,用例執行前先到我這
Children2 testDemoB
我是 Children2@After, 用例執行後到我這
我是 @After, 用例執行後到我這


我是 @Before,用例執行前先到我這
我是 Children2@Before,用例執行前先到我這
Children2 testDemoA
我是 Children2@After, 用例執行後到我這
我是 @After, 用例執行後到我這



java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:86)
    at org.junit.Assert.assertTrue(Assert.java:41)
    ...
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)


我是 @Before,用例執行前先到我這
我是 Children2@Before,用例執行前先到我這
testDemoA
我是 Children2@After, 用例執行後到我這
我是 @After, 用例執行後到我這



java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:86)
    at org.junit.Assert.assertTrue(Assert.java:41)
    ...
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)


我是 @Before,用例執行前先到我這
我是 Children2@Before,用例執行前先到我這
testDemoB
我是 Children2@After, 用例執行後到我這
我是 @After, 用例執行後到我這


我是 @Before,用例執行前先到我這
我是 Children2@Before,用例執行前先到我這
testDemoC
我是 Children2@After, 用例執行後到我這
我是 @After, 用例執行後到我這

我是 Children2@AfterClass,我是最後一步
我是 @AfterClass,我是最後一步
我是 @BeforeClass,我是第一步


我是 @Before,用例執行前先到我這
testDemoA
我是 @After, 用例執行後到我這



java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:86)
    at org.junit.Assert.assertTrue(Assert.java:41)
    ...
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)


我是 @Before,用例執行前先到我這
testDemoB
我是 @After, 用例執行後到我這


我是 @Before,用例執行前先到我這
testDemoC
我是 @After, 用例執行後到我這

我是 @AfterClass,我是最後一步
我是 @BeforeClass,我是第一步
我是 Children@BeforeClass,我是第一步


我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
Children testDemoB
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這


我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
Children testDemoA
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這



java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:86)
    at org.junit.Assert.assertTrue(Assert.java:41)
    at org.junit.Assert.assertTrue(Assert.java:52)
    ...
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)


我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
Children testDemoC
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這


我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
testDemoA
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這



java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:86)
    at org.junit.Assert.assertTrue(Assert.java:41)
    ...
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)


我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
testDemoB
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這


我是 @Before,用例執行前先到我這
我是 Children@Before,用例執行前先到我這
testDemoC
我是 Children@After, 用例執行後到我這
我是 @After, 用例執行後到我這

我是 Children@AfterClass,我是最後一步
我是 @AfterClass,我是最後一步

我是 @BeforeClass,我是第一步
我是 Children2@BeforeClass,我是第一步/<code> 


由測試結果可以看到使用套件後,測試過程為 Junit4DemoChildren2Test、Junit4DemoTest、Junit4DemoChildrenTest 的順序執行

2.8 分組測試-@Category

有時候我們需要對一些特定的用例進行分組測試,這個時候就可以用@Category來實現另外在套件執行類上運用註解:@RunWith(Categories.class) : 固定寫法,指明以 Category 方式分組@Categories.IncludeCategory(SlowGroup.class) : 指明要執行的測試分組包含哪些@Categories.ExcludeCategory(FastGroup.class) : 指明要執行的測試分組不包含哪些@Suite.SuiteClasses({ : 指明要執行的測試類 TestDemo.class})

  • @Category分組需要給定一個標籤,以類或者接口都可以,這裡創建連個接口SlowGroup和FastGrouppublic interface FastGroup {
    }
    public interface SlowGroup {
    }
  • 在用例上分別分組為SlowGroup、FastGroup和SlowGroup+FastGroup
如何利用 xUnit 框架對測試用例進行維護?

  • 指明SlowGroup組測試執行,FastGroup組的測試不執行:
如何利用 xUnit 框架對測試用例進行維護?


測試結果:

如何利用 xUnit 框架對測試用例進行維護?

  • 僅指明SlowGroup組測試執行
如何利用 xUnit 框架對測試用例進行維護?


測試結果:

如何利用 xUnit 框架對測試用例進行維護?

  • 僅指明不執行的組為FastGroup
如何利用 xUnit 框架對測試用例進行維護?


測試結果:

如何利用 xUnit 框架對測試用例進行維護?

2.9 參數化 @Paramterized

有時候我們需要傳入測試數據,且數據可能是多組,這個時候就需要使用參數化來傳入多組數據進行測試Junit4 的參數化稍微有點麻煩:

1)先在類名上加入註解@RunWith(Parameterized.class)表明要以參數化運行

如何利用 xUnit 框架對測試用例進行維護?

2)用註解@Parameterized.Parameters來設定數據源

如何利用 xUnit 框架對測試用例進行維護?

3)最後用註解 @Parameterized.Parameter 來指定數據源數據對應的參數

如何利用 xUnit 框架對測試用例進行維護?

4)總覽

如何利用 xUnit 框架對測試用例進行維護?

測試結果:

如何利用 xUnit 框架對測試用例進行維護?

從測試結果可以看到 3 組參數分別傳入方法中,方法各執行了一次,完成參數化測試

3、總結-測試用例的順序

  • 測試用例之間的順序
  • test fixtures 的順序
  • 繼承順序
  • 套件之間的順序

(文章來源於霍格沃茲測試學院)



分享到:


相關文章: