天天看點

Python之unittest架構的介紹及使用unittest介紹

目錄

  • unittest介紹
    • TestCase編寫
    • TestSuite與TextTestRunner
    • TestLoader
    • TestFixture
      • setUp和tearDown
      • setUpClass和tearDownClass
    • 斷言(重點)
      • assertEqual(a, b) 和 assertNotEqual(a, b)
      • assertTrue(x)和assertFalse(x)
      • assertIn(a, b)和assertNotIn(a, b)
    • 測試報告
      • 檔案方式的測試報告
      • HTML方式的測試報告
    • skip跳過用例

unittest介紹

unittest是Python自帶的一個單元測試架構, 它可以做單元測試, 也能用于編寫和運作重複的測試工作.

它給自動化測試用例開發和執行提供了豐富的斷言方法, 判斷測試用例是否通過, 并最終生成測試結果.

TestCase編寫

  • TestCase指的就是測試用例
  • 測試類必須繼承unittest.TestCase
  • 測試方法名稱命名必須以test開頭
  • 測試方法的執行順序有Case序号決定, 并非由代碼順序決定

一個簡單的例子:

# 1. 導入unittest
import unittest


# 2. 建立類繼承unittest.TestCase
class Test(unittest.TestCase):
    # 3. 建立測試用例方法, 方法要以test開頭
    # 執行順序是根據case序号來的, 并非代碼的順序
    def test_add_01(self):
        print(3+2)

    def test_add_02(self):
        print(10+5)
           

TestSuite與TextTestRunner

在上面提到, 測試用例的執行順序預設是由case序号決定的,但也可以使用TestSuite控制用例的執行順序。

  • TestSuite(測試套件)可以組織多個測試用例
  • TextTestRunner測試用例運作器
    • run()方法是測試用例的執行, 入參為suite測試套件

一個簡單的例子

# 1. 導入unittest
import unittest


# 2. 建立類繼承unittest.TestCase
class Test(unittest.TestCase):
    # 3. 建立測試用例方法, 方法要以test開頭
    # 執行順序是根據case序号來的, 并非代碼的順序
    def test_add_01(self):
        print(3+2)

    def test_add_02(self):
        print(10+5)

if __name__ == '__main__':
    suite = unittest.TestSuite()  # 執行個體化TestSuite
    suite.addTest(Test("test_add_02"))  # 添加測試用例
    suite.addTest(Test("test_add_01"))
    runner = unittest.TextTestRunner()  # 執行個體化TextTestRunner
    runner.run(suite)  # 傳入suite并執行測試用例
           

但是要注意, 如果在Pychram中直接右鍵運作, 它是不會執行main下面的内容, 需要修改pychram的運作方式

Python之unittest架構的介紹及使用unittest介紹

然後重新運作, 就會執行main下面的内容了.

重點,通常測試用例都是多個的,是以測試用例可以存放到清單中一次性添加到測試套件。這裡可以使用

suite.addTests()

case_list = ['Test("test_add_02")', Test("test_add_01")]
suite.addTests(case_list)
           

TestLoader

如果有多個測試檔案時, 可以使用TestLoader加載測試用例

  • unittest.defaultTestLoader

    , 使用discover()去加載測試用例
    • 找到指定目錄下所有測試子產品,并可遞歸查到子目錄下的測試子產品,隻有比對到檔案名才能被加載
  • discover(start_dir, pattern=‘test*.py’, top_level_dir=None)
    • start_dir:要測試的子產品名貨測試用例目錄
    • pattern=“test*.py”: 表示用例檔案名的比對原則。 此處比對檔案名以“test”開頭的“.py”類型的檔案,*表示任意字元
    • top_level_dir=None:測試子產品的頂層目錄, 如果沒有頂層目錄, 預設為None

一個小例子, 再目錄下建立多個test開頭的py檔案, 并且寫入測試方法

Python之unittest架構的介紹及使用unittest介紹

然後使用discover()方法讀取測試用例并執行

import unittest
# dicsover方法查找用例
suite = unittest.defaultTestLoader.discover("unittest_test", "test*.py")
# 2.TextTestRunner運作用例
runer = unittest.TextTestRunner()
runer.run(suite)
           

TestFixture

setUp和tearDown

setUp()方法

  • 主要是用來初始化測試環境, 它在每條測試用例執行前都會調用

tearDown()方法

  • 主要作用是測試用例執行完畢後恢複測試環境, 即使出現異常也會調用此方法,每條用例執行結束後都會運作

一個簡單的例子

import unittest

class Test(unittest.TestCase):
    def setUp(self) -> None:  # 調用setUp
        super().setUp()
        print("測試用例執行前操作")

    def test_add_01(self):
        print("num02")

    def test_add_02(self):
        print("num03")

    def tearDown(self) -> None:  # 調用tearDown
        super().tearDown()
        print("測試用例執行後操作")


# 傳回結果
測試用例執行前操作
num02
測試用例執行後操作
測試用例執行前操作
num03
測試用例執行後操作
           

在上面的傳回結果中可以明确的看出, 每條用例執行前都會先運作setUp,執行結束後都會運作tearDown

setUpClass和tearDownClass

setUpClass

  • 初始化測試環境且隻會執行一次。在類中需要加上@classmethod

tearDownClass

  • 恢複測試環境且隻會執行一次。在類中需要加上@classmethod
import unittest

class Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        super().setUpClass()
        print("測試前的操作")

    @classmethod
    def tearDownClass(cls) -> None:
        super().tearDownClass()
        print("測試後的操作")

    def test_add_01(self):
        print(3+2)

    def test_add_02(self):
        print(10+5)

# 傳回結果
測試前的操作
15
5
測試後的操作
           

從傳回結果可以看到setUpClass和tearDownClass都隻是執行了一次,與setUp和tearDown的結果有很明顯的差別。

注意,setUpClass和tearDownClass執行一次是針對目前的測試類而言的,如果目前的py檔案有多個測試類, 那麼它每個測試類都會執行一次。

如下:

# 1. 導入unittest
import unittest


# 2. 建立類繼承unittest.TestCase
class Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        super().setUpClass()
        print("測試前的操作")

    @classmethod
    def tearDownClass(cls) -> None:
        super().tearDownClass()
        print("測試後的操作")

    # 3. 建立測試用例方法, 方法要以test開頭
    # 執行順序是根據case序号來的, 并非代碼的順序

    def test_add_01(self):
        print(3+2)

    def test_add_02(self):
        print(10+5)


class Test2(unittest.TestCase):

    @classmethod
    def setUpClass(cls) -> None:
        super().setUpClass()
        print("測試前的操作2")

    @classmethod
    def tearDownClass(cls) -> None:
        super().tearDownClass()
        print("測試後的操作2")

    def test_add_03(self):
        print(20)

    def test_add_04(self):
        print(40)

if __name__ == '__main__':
    suite = unittest.TestSuite()  # 執行個體化TestSuite
    suite.addTests([Test("test_add_02"), Test("test_add_01"), Test2("test_add_03"), Test2("test_add_04")])  # 添加測試用例
    runner = unittest.TextTestRunner()  # 執行個體化TextTestRunner
    runner.run(suite)  # 傳入suite并執行測試用例
           

斷言(重點)

常用的斷言

方法 檢查
assertEqual(a, b) a == b
assertNotEqual(a, b) a != b
assertTrue(x) x的布爾值為真
assertFalse(x) x的布爾值為假
assertIn(a, b) a in b
assertNotIn(a, b) a not in b

assertEqual(a, b) 和 assertNotEqual(a, b)

# 1. 導入unittest
import unittest

# 2. 建立類繼承unittest.TestCase
class Test(unittest.TestCase):
    def setUp(self) -> None:
        super().setUp()
        print("測試開始")

    def test_add_01(self):
        print("1 == 1")
        self.assertEqual(1, 1)  # 成功

    def test_add_02(self):
        print("1 == 2")
        self.assertEqual(1, 2)  # 失敗

    def test_add_03(self):
        print("1 !=2 ")
        self.assertNotEqual(1, 2)  # 成功

    def test_add_04(self):
        print("1 != 1")
        self.assertNotEqual(1, 1)  # 失敗

    def tearDown(self) -> None:
        super().tearDown()
        print("測試結束")

           

assertTrue(x)和assertFalse(x)

class Test(unittest.TestCase):

    @classmethod
    def setUpClass(cls) -> None:
        super().setUpClass()
        print("測試前的操作2")

    @classmethod
    def tearDownClass(cls) -> None:
        super().tearDownClass()
        print("測試後的操作2")

    def test_05(self):
        self.assertTrue(1 < 2)  # 成功

    def test_06(self):
        self.assertTrue(1 > 2)  # 失敗

    def test_07(self):
        self.assertFalse(1 > 2)  # 成功

    def test_08(self):
        self.assertFalse(1 < 2)  # 失敗
           

assertIn(a, b)和assertNotIn(a, b)

import unittest

class Test(unittest.TestCase):

    @classmethod
    def setUpClass(cls) -> None:
        super().setUpClass()
        print("測試前的操作2")

    @classmethod
    def tearDownClass(cls) -> None:
        super().tearDownClass()
        print("測試後的操作2")

    def test_09(self):
        self.assertIn("a", "abc")  # 成功

    def test_10(self):
        self.assertIn("a", "bcd")  # 失敗

    def test_11(self):
        self.assertNotIn("a", "bcd")  # 成功

    def test_12(self):
        self.assertNotIn("a", "abc")  # 失敗
           

測試報告

檔案方式的測試報告

import unittest
# dicsover方法查找用例
suite = unittest.defaultTestLoader.discover("unittest_test", "test*.py")
# 打開檔案對象
with open("test_report.txt", "a") as f:
    # TextTestRunner運作用例
    runer = unittest.TextTestRunner(stream=f, verbosity=2)  # verbosity=2 輸出詳細日志
    runer.run(suite)
           

HTML方式的測試報告

HTML報告需要導入HTMLTestRunner.py,這個檔案原本隻支援python2,python3需要修改部分代碼才能使用。

然後我發現CSDN這裡已經有人上傳過這個資源了, 不過貌似要收費, 我這裡也傳一個網盤吧, 這是已經修改好支援python的, 直接使用就行。

連結:https://pan.baidu.com/s/171jiRp9lw8Gtrl140g0uJw 
提取碼:64db
           

回到正題,HTMLTestRunner的用法其實和TextTestRunner的差不多, 代碼如下:

import unittest
from lib.HTMLTestRunner import HTMLTestRunner
# dicsover方法查找用例
suite = unittest.defaultTestLoader.discover("unittest_test", "test*.py")

with open("test_report.html", "wb") as report:
    runner = HTMLTestRunner(stream=report, verbosity=2, title="HTML測試報告", description="這是練習的測試報告")
    runner.run(suite)
           

運作結束後在本地就會看到多了一個HTML檔案,打開就能看到測試報告了

Python之unittest架構的介紹及使用unittest介紹

skip跳過用例

在遇到不想執行的測試用例時,可以使用skip方法

  • @unittest.skip(reason)

    :無條件跳過用例, reason是說明原因
  • @unittest.skipIf(condition, reason)

    :condition為true時跳過用例
  • @ unittest.skipUnless(condition, reason)

    :condition為False的時候跳過

執行個體代碼:

# 1. 導入unittest
import unittest

class Test(unittest.TestCase):

    @classmethod
    def setUpClass(cls) -> None:
        super().setUpClass()
        print("測試前的操作2")

    @classmethod
    def tearDownClass(cls) -> None:
        super().tearDownClass()
        print("測試後的操作2")
        
    @unittest.skip("無條件跳過")
    def test_09(self):
        self.assertIn("a", "abc")
        
    @unittest.skipIf(2>1, "因為2>1是以跳過")
    def test_10(self):
        self.assertIn("a", "bcd")
        
    @unittest.skipUnless(1>2, "因為1>2為假,是以跳過")
    def test_11(self):
        self.assertNotIn("a", "bcd")

    def test_12(self):
        self.assertNotIn("a", "abc")
           

然後執行用例并生成測試報告

import unittest
from lib.HTMLTestRunner import HTMLTestRunner
# dicsover方法查找用例
suite = unittest.defaultTestLoader.discover("unittest_test", "test*.py")

with open("test_report.html", "wb") as report:
    runner = HTMLTestRunner(stream=report, verbosity=2, title="HTML測試報告", description="這是練習的測試報告")
    runner.run(suite)
           

測試報告,隻剩下了一個測試用例了

Python之unittest架構的介紹及使用unittest介紹