Python unittest

Python unittest

unittest 是Python 自帶的單元測試框架,用它來作單元測試,它裏面封裝好了一些校驗返回的結果方法和一些用例運行前的初始化操做。
官方文檔:https://docs.python.org/3/library/unittest.html#module-unittesthtml

簡介

unittest 中有一些類:python

TestCase 測試用例
TestSuite 多個測試用例集合在一塊兒,就是TestSuite
TestLoader 用來加載 TestCase 到 TestSuite 中的
TestRunner 是來運行測試用例的, 測試的結果會保存到 TestResult 實例中,包括運行了多少測試用例,成功了多少,失敗了多少等信息正則表達式

使用

unittest 要求單元測試類必須繼承 unittest.TestCase,該類中的測試方法須要知足以下要求:框架

  • 沒有返回值
  • 不該該有任何參數
  • 應以test 開頭

示例:函數

import unittest


class TestFunc(unittest.TestCase):
    def test_1(self):
        self.assertEqual(func1(1, 1), 2)

    def test_2(self):
        self.assertEqual(func1(1, 2), 3)


def func1(a, b):
    return a + b


if __name__ == '__main__':
    unittest.main()

返回結果:單元測試

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

斷言方法

經常使用的方法:測試

斷言方法 檢查條件
assertEqual(a, b) a == b
assertNotEqual(a, b) a != b
assertTrue(x) bool(x) is True
assertFalse(x) bool(x) is False
assertIs(a, b) a is b
assertIsNot(a, b) a is not b
assertIsNone(x) x is None
assertIsNotNone(x) x is not None
assertIn(a, b) a in b
assertNotIn(a, b) a not in b
assertlsInstance(a, b) isinstance(a, b)
assertNotIsInstance(a, b) not isinstance(a, b)

包含檢查 exceptions, warnings, and log messages 的方法:ui

斷言方法 檢查條件
assertRaises(exc, fun, \*args, \*\*kwds) fun(\*args, \*\*kwds) raises exc 異常
assertRaisesRegex(exc, r, fun, \*args, \*\*kwds) fun(\*args, \*\*kwds) raises exc 異常,且異常信息匹配正則表達式 r
assertWarns(warn, fun, \*args, \*\*kwds) fun(\*args, \*\*kwds) raises warn 警告
assertWarnsRegex(warn, r, fun, \*args, \*\*kwds) fun(\*args, \*\*kwds) raises warn 警告,且異常信息匹配正則表達式 r
assertLogs(logger, level) with 語句塊使用日誌器 (logger) 生成 level 級別的日誌

包含特定檢查的方法:日誌

斷言方法 檢查條件
assertAlmostEqual(a, b) round(a-b, 7) == 0
assertNotAlmostEqual(a, b) round(a-b, 7) != 0
assertGreater(a, b) a > b
assertGreaterEqual(a, b) a >= b
assertLess(a, b) a < b
assertLessEqual(a, b) a <= b
assertRegex(s, r) r.search(s)
assertNotRegex(s, r) not r.search(s)
assertCountEqual(a, b) a、b 包含的元素及其數量相同,無視順序 等效於`assertEqual(Counter(list(first)), Counter(list(second)))`

返回結果

第一行表示每一個測試用例的運行結果:code

從第一個開始表示相應順序的測試用例運行結果
.: 測試經過
F: FAILURE 測試失敗
E: ERROR 測試出錯
S: Skip 跳過該測試

以後是錯誤信息 (若是有的話):
示例:

======================================================================
ERROR: test_1 (__main__.TestFunc)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 30, in func1
    raise IndexError
IndexError
======================================================================
FAIL: test_2 (__main__.TestFunc)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "text.py", line 27, in test_2
    self.assertEqual(func1(1, 2), 4)
AssertionError: 3 != 4

若是是測試出錯,會將錯誤顯示出來
若是是測試失敗,會將失敗緣由以及函數運行的實際結果和指望結果的差別顯示出來

最後是全部測試用例的運行結果:

示例:

----------------------------------------------------------------------
Ran 3 tests in 0.000s

FAILED (failures=1, errors=1)
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

會顯示本次測試一共運行了幾個測試用例,以及運行時間
最後是運行的結果
OK: 全部測試用例均經過
FAILED: 沒有所有經過 (以及失敗數量和錯誤數量)

運行順序

在 TestCase 中有一些特殊的方法:
setUp: 每一個測試用例以前運行
tearDown: 每一個測試用例以後運行
setUpClass: 全部測試用例以前 (setUp) 運行
tearDownClass: 全部測試用例以後 (tearDown) 運行

運行順序示例:

import unittest


class TestFunc(unittest.TestCase):
    def tearDown(self) -> None:
        print('from tearDown')

    def setUp(self) -> None:
        print('from setUp')

    @classmethod
    def tearDownClass(cls) -> None:
        print('from tearDownClass')

    @classmethod
    def setUpClass(cls) -> None:
        print('from setUpClass')

    def test_1(self):
        self.assertEqual(func1(1, 1), 2)

    def test_2(self):
        self.assertEqual(func1(1, 2), 3)


def func1(a, b):
    return a + b


if __name__ == '__main__':
    unittest.main()

返回結果

from setUpClass
..
from setUp
----------------------------------------------------------------------
from tearDown
Ran 2 tests in 0.000s
from setUp

from tearDown
from tearDownClass
OK

運行多個測試用例

使用 unittest.main() 會直接運行全部的測試用例,若是但願只運行一些特定的測試用例,就須要用到 TestSuite
TestSuite 是許多測試用例的集合,經過 addTest() 方法將測試用例添加到 TestSuite
以後實例化一個 TextTestRunner(TestRunner) 類,最後調用 run() 就能夠運行測試用例了

示例:

import unittest
from typing import Any
# import HTMLTestRunner


class MyTestFunc1(unittest.TestCase):
    def test_1(self):
        print('from Func1 test_1')
        self.assertEqual(func1(1, 1), 2)

    def test_2(self):
        print('from Func1 test_2')
        self.assertNotEqual(func1(1, 2), 4)


class MyTestFunc2(unittest.TestCase):
    def test_1(self):
        print('from Func2 test_1')
        self.assertTrue(func1(1, 2))


def func1(a, b):
    return a + b


if __name__ == '__main__':
    test_suite = unittest.TestSuite()
    test_suite.addTest(unittest.makeSuite(MyTestFunc2))
    test_suite.addTest(MyTestFunc1('test_1'))
    runner = unittest.TextTestRunner()
    runner.run(test_suite)

返回結果:

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
from Func2 test_1
from Func1 test_1

能夠看出只有 MyTestFunc1 中的 test_1 和 MyTestFunc2 中的 test_1 運行了
而且運行順序取決於添加到 TestSuite 中的順序

獲取報告

經過 TextTestRunner 類能夠將測試結果儲存到文件中,而不是直接打印出來,只須要實例化時傳入相關參數便可

f = open('report.txt', 'w')
runner = unittest.TextTestRunner(stream=f)

還有一些其餘的參數,能夠在 TextTestRunner 類源碼中看到

其餘模塊

經過其餘模塊能夠獲取其餘格式的測試結果
這些模塊須要單獨安裝 HTMLTestRunnerxmlrunner
使用方法類似,實例化時傳入必要的參數,以後調用 run() 方法便可

相關文章
相關標籤/搜索