unittest
基本概念
-
test fixture 测试夹具
测试预先操作以及测试的后置操作
-
test case 测试用例
测试用例 unittes 提供一个基础类TestCase
-
test suit 测试套
测试用例的集合容器,聚集要一起执行的用例
-
test runner 测试运行器
协调测试执行并向用户提供结果的组件
simlpe example
import unittest
class TestNumber(unittest.TestCase):
def test_01(self):
self.assertEqual(1, 1)
def test_02(self):
self.assertFalse(1==2)
if __name__ == "__main__":
unittest.main()
# ..
# ----------------------------------------------------------------------
# Ran 2 tests in 0.000s
# OK
- 测试类继承unittest.Testcase
- 测试方法名test开头
命令行接口
python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
python -m unittest tests/test_something.py
(.venv) PS D:\project\howtospider> python -m unittest main.TestNumber.test_01
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
当没有参数时候 测试发现被启动
命令行选项 以及测试发现选项
(.venv) PS D:\project\howtospider> python -m unittest -h
usage: python.exe -m unittest [-h] [-v] [-q] [--locals] [--durations N] [-f] [-c] [-b] [-k TESTNAMEPATTERNS] [tests ...]
positional arguments:
tests a list of any number of test modules, classes and test methods.
options:
-h, --help show this help message and exit
-v, --verbose Verbose output 显示详细信息
-q, --quiet Quiet output 显示简略信息
--locals Show local variables in tracebacks 在tracebacks中显示变量
--durations N Show the N slowest test cases (N=0 for all) 显示最慢的几个测试用例
-f, --failfast Stop on first fail or error 遇到第一个失败的用例就停止
-c, --catch Catch Ctrl-C and display results so far 按ctrl c 运行完当前用例结束则返回测试结果, 再按ctrl c 就触发KeyboardInterrupt异常
-b, --buffer Buffer stdout and stderr during tests 缓存标准输出 错误输出
-k TESTNAMEPATTERNS Only run tests which match the given substring 运行符合关键词的用例
Examples:
python.exe -m unittest test_module - run tests from test_module
python.exe -m unittest module.TestClass - run tests from module.TestClass
python.exe -m unittest module.Class.test_method - run specified test method
python.exe -m unittest path/to/test_file.py - run tests from test_file.py
usage: python.exe -m unittest discover [-h] [-v] [-q] [--locals] [--durations N] [-f] [-c] [-b] [-k TESTNAMEPATTERNS] [-s START] [-p PATTERN] [-t TOP]
options:
-h, --help show this help message and exit
-v, --verbose Verbose output
-q, --quiet Quiet output
--locals Show local variables in tracebacks
--durations N Show the N slowest test cases (N=0 for all)
-f, --failfast Stop on first fail or error
-c, --catch Catch Ctrl-C and display results so far
-b, --buffer Buffer stdout and stderr during tests
-k TESTNAMEPATTERNS Only run tests which match the given substring
-s START, --start-directory START
Directory to start discovery ('.' default)
-p PATTERN, --pattern PATTERN
Pattern to match tests ('test*.py' default)
-t TOP, --top-level-directory TOP
Top level directory of project (defaults to start directory)
For test discovery all test modules must be importable from the top level directory of the project.
python -m unittest discover -s project_directory -p "*_test.py"
python -m unittest discover project_directory "*_test.py"
组织测试
测试夹具
import unittest
class TestNumber(unittest.TestCase):
def setUp(self):
print('setUp-----------')
def test_01(self):
print('test_01')
self.assertEqual(1, 1)
def test_02(self):
print('test_02')
self.assertFalse(1==2)
def tearDown(self):
print('tearDown---------')
# setUp-----------
# test_01
# tearDown---------
# .setUp-----------
# test_02
# tearDown---------
# .
# ----------------------------------------------------------------------
# Ran 2 tests in 0.001s
# OK
testsuit
from pdb import run
import unittest
class TestCase01(unittest.TestCase):
def test_01(self):
print('TestCase01_test_01')
def test_02(self):
print('TestCase01_test_02')
class TestCase02(unittest.TestCase):
def test_01(self):
print('TestCase02_test_01')
def test_02(self):
print('TestCase02_test_02')
def suite():
suite = unittest.TestSuite()
suite.addTest(TestCase01('test_01'))
suite.addTest(TestCase02('test_01'))
return suite
if __name__ == "__main__":
runner = unittest.TextTestRunner()
runner.run(suite())
# TestCase01_test_01
# .TestCase02_test_01
# .
# ----------------------------------------------------------------------
# Ran 2 tests in 0.001s
# OK
function to TestCase
from pdb import run
import unittest
def testsomething():
assert 1 == 1
def beforetest():
print('beforetest')
def aftertest():
print('aftertest')
testcase = unittest.FunctionTestCase(testsomething, setUp=beforetest, tearDown=aftertest)
def suite():
suite = unittest.TestSuite()
suite.addTest(testcase)
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
# beforetest
# aftertest
# .
# ----------------------------------------------------------------------
# Ran 1 test in 0.001s
# OK
跳过用例和预期错误
# @unittest.skip("showing class skipping")
class MyTestCase(unittest.TestCase):
@unittest.skip("demonstrating skipping")
def test_nothing(self):
self.fail("shouldn't happen")
@unittest.skipIf(mylib.__version__ < (1, 3),
"not supported in this library version")
def test_format(self):
# Tests that work for only a certain version of the library.
pass
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
def test_windows_support(self):
# windows specific testing code
pass
def test_maybe_skipped(self):
if not external_resource_available():
self.skipTest("external resource not available")
# test code that depends on the external resource
pass
class ExpectedFailureTestCase(unittest.TestCase):
@unittest.expectedFailure
def test_fail(self):
self.assertEqual(1, 0, "broken")
# 自定义装饰器
def skipUnlessHasattr(obj, attr):
if hasattr(obj, attr):
return lambda func: func
return unittest.skip("{!r} doesn't have {!r}".format(obj, attr))
子测试
class NumbersTest(unittest.TestCase):
def test_even(self):
"""
Test that numbers between 0 and 5 are all even.
"""
for i in range(0, 6):
with self.subTest(i=i):
self.assertEqual(i % 2, 0)
# FFF
# ======================================================================
# FAIL: test_even (main.NumbersTest.test_even) (i=1)
# Test that numbers between 0 and 5 are all even.
# ----------------------------------------------------------------------
# Traceback (most recent call last):
# File "D:\project\howtospider\main.py", line 11, in test_even
# self.assertEqual(i % 2, 0)
# AssertionError: 1 != 0
# ======================================================================
# FAIL: test_even (main.NumbersTest.test_even) (i=3)
# Test that numbers between 0 and 5 are all even.
# ----------------------------------------------------------------------
# Traceback (most recent call last):
# File "D:\project\howtospider\main.py", line 11, in test_even
# self.assertEqual(i % 2, 0)
# AssertionError: 1 != 0
# ======================================================================
# FAIL: test_even (main.NumbersTest.test_even) (i=5)
# Test that numbers between 0 and 5 are all even.
# ----------------------------------------------------------------------
# Traceback (most recent call last):
# File "D:\project\howtospider\main.py", line 11, in test_even
# self.assertEqual(i % 2, 0)
# AssertionError: 1 != 0
# ----------------------------------------------------------------------
# Ran 1 test in 0.001s
# FAILED (failures=3)