unittest介绍
unittest
是Python标准库中自带的单元测试框架。unittest
单元测试框架不仅可以适用于单元测试,还可以适用于接口测试、UI自动化测试等,它有一个很重要的特性:它是通过类(class
)的方式将测试用例组织在一起。
什么是单元测试?
单元测试是开发者编写的一段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或场景)下某个特定函数的行为。
什么是框架?
框架就是业内大佬定制研发的应用骨架,它对基础代码进行了封装并且提供一些API接口。其他开发者只需要直接调用封装好的API接口即可。可以节省普通开发者的很多代码编写,从而提升工作效率。
unittest核心工作原理
unittest
中最核心的四个概念是:test case
, test suite
, test runner
,test fixture
。
TestCase
:测试用例,测试用例中会有很多测试方法,是单元测试中最小维度的测试行为。一个测试用例就是一个完整的测试单元,包括测试前准备的搭建(setUp
)、执行测试代码(run
),以及测试后环境的还原(tearDown
)。TestSuite
:多个测试用例集合在一起,就是TestSuite
,可以批量执行一个测试套件内所有的测试用例,而且TestSuite
也可以嵌套TestSuite
TestRunner
:测试的执行也是单元测试中非常重要的一个概念,一般单元测试框架中都会提供丰富的执行策略和执行结果。在unittest
单元测试框架中,通过TextTestRunner
类提供的run()
方法来执行testsuite
/testcase
。testrunner
可以使用图形界面,文本界面,或返回一个特殊的值等方式来表示测试执行的结果。TestFixture
:对一个测试用例环境的搭建和销毁,是一个fixture
,通过覆盖TestCase
的setUp()
和tearDown()
方法来实现。用途是比如说在这个测试用例中需要访问数据库,那么可以在setUp()
中建立数据库连接以及进行一些初始化,在tearDown()
中清除在数据库中产生的数据,然后关闭连接。注意tearDown
的过程很重要,要为以后的TestCase
留下一个干净的环境。(Fixture
很多资料翻译成夹具)
另,TestLoader
也是比较重要的概念。TestLoader
是用来加载TestCase
到TestSuite
中的,其中有几个loadTestsFrom__()
方法,就是从各个地方寻找TestCase
,创建它们的实例,然后add
到TestSuite
中,再返回一个TestSuite
实例
注:
unittest
的核心组件一共是5个,但很多资料上写的是4个,没有将TestLoader
算在内。可以通过
dir
命令查看unittest
的属性和方法>>> import unittest >>> dir(unittest) ['BaseTestSuite', 'FunctionTestCase', 'IsolatedAsyncioTestCase', 'SkipTest', 'TestCase', 'TestLoader', 'TestProgram', 'TestResult', 'TestSuite', 'TextTestResult', 'TextTestRunner', '_TextTestResult', '__all__', '__builtins__', '__cached__', '__dir__', '__doc__', '__file__', '__getattr__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__unittest', 'addModuleCleanup', 'case', 'defaultTestLoader', 'expectedFailure', 'findTestCases', 'getTestCaseNames', 'installHandler', 'load_tests', 'loader', 'main', 'makeSuite', 'registerResult', 'removeHandler', 'removeResult', 'result', 'runner', 'signals', 'skip', 'skipIf', 'skipUnless', 'suite', 'util']
其中,下面几个是比较重要的:
unittest.TestCase
:TestCase
类,所有测试用例类都要继承的基类;
unittest.TestSuite()
:unittest
框架的TestSuite()
类是用来创建测试套件的;
unittest.main()
:将一个单元测试模块变成可直接运行的测试脚本,main()
方法使用TestLoader
类来搜索所有包含在该模块中“test”命名开头的测试方法,并自动执行它们,根据ASCII码的顺序加载测试用例;
unittest.TextTestRunner
:unittest
框架的TextTestRunner()
类,通过该类下面的run()
方法来运行suite
所组装的测试用例,入参为suite
测试套件;
unittest
框架的使用步骤:
- 设计测试用例:通过继承
unittest.TestCase
设计具体的测试用例; - 搜集测试用例:从多个py文件中收集并加载测试用例;
- 执行测试用例:将测试用例按照一定的顺序去执行并生成结果;
- 测试结果判断:通过断言去判断结果是正确;
- 输出测试结果:统计测试进度,通过率,生成报告;
TestCase测试用例
测试用例编写规范:
- 测试模块需要导入
uniitest
:import unittest
- 测试类必须继承
unittest.TestCase
- 测试方法必须以
test
开头 - 测试用例执行的默认顺序是按照ASCII码的顺序执行的
0~9 A~Z a~z
- 在测试函数中使用断言来判断测试结果是否符合预期结果 (没有进行合理的断言不能称之为测试用例)
基于一个虚拟的PLS系统来进行测试用例的设计
- 设计登录的测试用例
import unittest
class PlsLogin(unittest.TestCase):
# 测试用例01-测试老百登录
def test_01_laobai(self):
print("测试老百登录")
# 测试用例02-测试nichengwe登录
def test_02_nichengwe(self):
print("测试nichengwe登录")
- 测试执行
测试执行可以通过以下几种方式进行:
a. 执行某个类中的某个测试方法: Pycharm
IDE的代码编辑器区,将光标放在要执行的某个测试方法中,右键运行“Run ‘Python tests for pls…’”

运行结果如下:
Testing started at 16:47 ...
Launching unittests with arguments python -m unittest pls_login.PlsLogin.test_01_laobai in /Users/laobai/workspaces/testdemo01/unittestdemo
Ran 1 test in 0.003s
测试老百登录
OK
Process finished with exit code 0
b. 执行某个类中的全部测试方法: Pycharm
IDE的代码编辑器区,将光标放在要执行类名附近,右键运行“Run ‘Python tests for pls…’”

运行结果如下:
Testing started at 18:07 ...
Launching unittests with arguments python -m unittest pls_login.PlsLogin in /Users/laobai/workspaces/testdemo01/unittestdemo
Ran 2 tests in 0.004s
OK
测试老百登录
测试nichengwe登录
Process finished with exit code 0
注:观察上面两种运行方式的输出结果,有两处输出内容需要注意
Launching unittests with arguments python -m unittest pls_login.PlsLogin.test_01_laobai in /Users/laobai/workspaces/testdemo01/unittestdemo
Launching unittests with arguments python -m unittest pls_login.PlsLogin in /Users/laobai/workspaces/testdemo01/unittestdemo
其中/Users/laobai/workspaces/testdemo01/unittestdemo
是当前执行的测试用例所在的模块名(文件名)
而python -m unittest pls_login.PlsLogin.test_01_laobai
和python -m unittest pls_login.PlsLogin
是执行上面两个测试用例的命令。
先确保当前目录为/Users/laobai/workspaces/testdemo01/unittestdemo
$ python -m unittest pls_login.PlsLogin.test_01_laobai
测试老百登录
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
$ python -m unittest pls_login.PlsLogin
测试老百登录
.测试nichengwe登录
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
注:python命令的参数
-m
:通过查看python的帮助文档可知为“以(二进制)脚本的形式去运行一个模块”
$ python --help usage: /Users/laobai/workspaces/testdemo01/venv/bin/python [option] ... [-c cmd | -m mod | file | -] [arg] ... ... -m mod : run library module as a script (terminates option list) ...
c. 在上面两种方式的基础上,可以为unittest
增加-v
参数来获得更详细的输出结果信息
-v
: --verbose
意思就是更详细的输出结果
$ python -m unittest -v pls_login.PlsLogin
test_01_laobai (pls_login.PlsLogin) ... 测试老百登录
ok
test_02_nichengwe (pls_login.PlsLogin) ... 测试nichengwe登录
ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
之前测试结果只显示两个点,增加了-v
参数后,会显示具体测试的那个方法及所属类
在步骤1的基础上,在代码中增加
main
如下:import unittest class PlsLogin(unittest.TestCase): # 测试用例01-测试老百登录 def test_01_laobai(self): print("测试老百登录") # 测试用例02-测试nichengwe登录 def test_02_nichengwe(self): print("测试nichengwe登录") if __name__ == '__main__': unittest.main()
增加的
main
对于上面两种通过在IDE中进行运行单元测试的方式没有影响。增加了main
可以用如下命令在命令行中进行执行测试$ python pls_login.py 测试老百登录 .测试nichengwe登录 . ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
当然也可以增加
-v
参数$ python pls_login.py -v test_01_laobai (__main__.PlsLogin) ... 测试老百登录 ok test_02_nichengwe (__main__.PlsLogin) ... 测试nichengwe登录 ok ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
当然,也可以在IDE中,通过在
main
来执行用例注意:在命令行或
main
中可以添加verbosity
参数来表示测试结果的信息复杂度,有0,1,2三个值 0:静默模式,只能获得总的测试用例数和总的结果,比如一共10个用例,成功8个,失败1个,错误1个;
1:默认模式,几乎与静默模式相同,成功的用例显示成
.
,失败的用例显示成F
,错误的用例显示成E
; 2:详细模式,测试结果会显示每个测试用例的所有相关信息;
在
main
中书写格式为unittest.main(verbosity=2)
而在命令行模式中,
什么参数都不加,即为静默模式,等效于
verbosity=1
增加
--quiet
或-q
参数,即静默模式,等效于verbosity=0
增加
--verbose
或-v
参数,即为详细模式,等效于verbosity=2
测试结果
通过上面的执行的测试用例发现,会有如下的测试结果:
.
:成功import unittest class PlsLogin(unittest.TestCase): # 测试用例01-测试老百登录 def test_01_laobai(self): print("测试老百登录") # 测试用例02-测试nichengwe登录 def test_02_nichengwe(self): print("测试nichengwe登录") if __name__ == '__main__': unittest.main() $ python pls_login.py 测试老百登录 .测试nichengwe登录 . ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
E
:错误import unittest class PlsLogin(unittest.TestCase): # 测试用例01-测试老百登录 def test_01_laobai(self): raise Exception("自定义异常") print("测试老百登录") # 测试用例02-测试nichengwe登录 def test_02_nichengwe(self): print("测试nichengwe登录") if __name__ == '__main__': unittest.main() $ python pls_login.py E测试nichengwe登录 . ====================================================================== ERROR: test_01_laobai (__main__.PlsLogin) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/laobai/workspaces/testdemo01/unittestdemo/pls_login.py", line 11, in test_01_laobai raise Exception("自定义异常") Exception: 自定义异常 ---------------------------------------------------------------------- Ran 2 tests in 0.000s FAILED (errors=1)
F
:失败import unittest class PlsLogin(unittest.TestCase): # 测试用例01-测试老百登录 def test_01_laobai(self): print("测试老百登录") self.assertTrue(0) # 测试用例02-测试nichengwe登录 def test_02_nichengwe(self): print("测试nichengwe登录") if __name__ == '__main__': unittest.main() $ python pls_login.py 测试老百登录 F测试nichengwe登录 . ====================================================================== FAIL: test_01_laobai (__main__.PlsLogin) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/laobai/workspaces/testdemo01/unittestdemo/pls_login.py", line 12, in test_01_laobai self.assertTrue(0) AssertionError: 0 is not true ---------------------------------------------------------------------- Ran 2 tests in 0.001s FAILED (failures=1)
S
:跳过import unittest class PlsLogin(unittest.TestCase): # 测试用例01-测试老百登录 @unittest.skip("此用例不执行") def test_01_laobai(self): print("测试老百登录") # 测试用例02-测试nichengwe登录 def test_02_nichengwe(self): print("测试nichengwe登录") if __name__ == '__main__': unittest.main() $ python pls_login.py s测试nichengwe登录 . ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK (skipped=1)
测试用例的执行顺序
a. 默认顺序是按照ASCII码的顺序执行的
0~9 A~Z a~z
b. 在测试用例用例方法命名时,可以增加序号来自定义顺序,比如上面的例子:
test_01_laobai
,test_02_nichengwe
TestSuite测试套件
上面的例子简单说明了编写一个简单的单一的测试,按照默认的顺序执行测试用例,若是要自定义测试用例的执行顺序,就需要用到了TestSuite
,添加到TestSuite
中的测试用例会按照添加的顺序进行执行的。测试用例存在多个文件中,也可以用TestSuite
来组织执行。
使用TestSuite
测试套件的步骤:
- 定义测试套件(
suite = unittest.TestSuite()
) - 向测试套件中添加测试用例(按照添加顺序执行)
- 运行套件中的用例
先写两个测试用例:
pls_register.py
import unittest
class PlsRegister(unittest.TestCase):
# 测试用例01-测试注册账号-老百
def test_01_laobai(self):
print("测试注册账号-老百")
# 测试用例02-测试注册账号-nichengwe
def test_02_nichengwe(self):
print("测试注册账号-nichengwe")
# 测试用例03-测试注册账号-baby2016
def test_03_baby2016(self):
print("测试注册账号-baby2016")
if __name__ == '__main__':
unittest.main(verbosity=2)
pls_login.py
import unittest
class PlsLogin(unittest.TestCase):
# 测试用例01-测试老百登录
def test_01_laobai(self):
print("测试老百登录")
# 测试用例02-测试nichengwe登录
def test_02_nichengwe(self):
print("测试nichengwe登录")
# 测试用例02-测试baby2016登录
def test_03_baby2016(self):
print("测试baby2016登录")
if __name__ == '__main__':
unittest.main(verbosity=2)
addTest
通过使用addTest
向测试套件中添加用例,每次添加一个用例,测试执行时按照添加用例的顺序执行。
import unittest
class PlsRegister(unittest.TestCase):
# 测试用例01-测试注册账号-老百
def test_01_laobai(self):
print("测试注册账号-老百")
# 测试用例02-测试注册账号-nichengwe
def test_02_nichengwe(self):
print("测试注册账号-nichengwe")
# 测试用例03-测试注册账号-baby2016
def test_03_baby2016(self):
print("测试注册账号-baby2016")
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(PlsRegister('test_02_nichengwe'))
suite.addTest(PlsRegister('test_03_baby2016'))
suite.addTest(PlsRegister('test_01_laobai'))
unittest.main(defaultTest='suite', verbosity=2)
# unittest.TextTestRunner(verbosity=2).run(suite)
执行结果如下:
测试注册账号-nichengwe
测试注册账号-baby2016
测试注册账号-老百
test_02_nichengwe (__main__.PlsRegister) ... ok
test_03_baby2016 (__main__.PlsRegister) ... ok
test_01_laobai (__main__.PlsRegister) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
Process finished with exit code 0
可以看到执行的结果是按照添加到套件里的顺序进行的。
unittest.main(defaultTest='suite', verbosity=2)
和unittest.TextTestRunner(verbosity=2).run(suite)
两种写法都可以。
注意:
在PycharmIDE中执行测试用例时,可能会出现添加了部分用例或者某种顺序,但执行的时候是全部用例及默认顺序执行的。(在命令行中执行是正确的,按照添加到套件的顺序执行)

这里需要编辑修改Edit Configurations
,新建一个python
的configuration
,在Script path
中选择对应的文件

然后在IDE中选择新建的configuration
,通过右侧的执行按钮进行用例的执行即可。

addTests
可以通过addTests
批量添加多个用例
import unittest
class PlsRegister(unittest.TestCase):
# 测试用例01-测试注册账号-老百
def test_01_laobai(self):
print("测试注册账号-老百")
# 测试用例02-测试注册账号-nichengwe
def test_02_nichengwe(self):
print("测试注册账号-nichengwe")
# 测试用例03-测试注册账号-baby2016
def test_03_baby2016(self):
print("测试注册账号-baby2016")
if __name__ == '__main__':
suite = unittest.TestSuite()
testcases = [PlsRegister('test_02_nichengwe'), PlsRegister('test_01_laobai'), PlsRegister('test_03_baby2016')]
suite.addTests(testcases)
unittest.main(defaultTest='suite', verbosity=2)
执行结果:
test_02_nichengwe (__main__.PlsRegister) ... ok
test_01_laobai (__main__.PlsRegister) ... ok
test_03_baby2016 (__main__.PlsRegister) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
测试注册账号-nichengwe
测试注册账号-老百
测试注册账号-baby2016
Process finished with exit code 0
也可以跨文件进行添加:
import pls_register
import unittest
class PlsLogin(unittest.TestCase):
# 测试用例01-测试老百登录
def test_01_laobai(self):
print("测试老百登录")
# 测试用例02-测试nichengwe登录
def test_02_nichengwe(self):
print("测试nichengwe登录")
# 测试用例02-测试baby2016登录
def test_03_baby2016(self):
print("测试baby2016登录")
if __name__ == '__main__':
suite = unittest.TestSuite()
testcases = [pls_register.PlsRegister('test_02_nichengwe'), pls_register.PlsRegister('test_01_laobai'), pls_register.PlsRegister('test_03_baby2016'),PlsLogin('test_03_baby2016'),PlsLogin('test_01_laobai'),PlsLogin('test_02_nichengwe')]
suite.addTests(testcases)
unittest.main(defaultTest='suite', verbosity=2)
运行结果:
$ python pls_login.py
test_02_nichengwe (pls_register.PlsRegister) ... 测试注册账号-nichengwe
ok
test_01_laobai (pls_register.PlsRegister) ... 测试注册账号-老百
ok
test_03_baby2016 (pls_register.PlsRegister) ... 测试注册账号-baby2016
ok
test_03_baby2016 (__main__.PlsLogin) ... 测试baby2016登录
ok
test_01_laobai (__main__.PlsLogin) ... 测试老百登录
ok
test_02_nichengwe (__main__.PlsLogin) ... 测试nichengwe登录
ok
----------------------------------------------------------------------
Ran 6 tests in 0.001s
ok
discover
上面的两个例子是添加多个用例,但用例过多时会比较繁琐。可以使用discover
自动搜寻测试用例
discover()
有两个参数start_dir
在哪个目录搜索和pattern
在哪个文件下搜索,pattern
的默认取值是'test*.py'
import os
import unittest
class PlsLogin(unittest.TestCase):
# 测试用例01-测试老百登录
def test_01_laobai(self):
print("测试老百登录")
# 测试用例02-测试nichengwe登录
def test_02_nichengwe(self):
print("测试nichengwe登录")
# 测试用例02-测试baby2016登录
def test_03_baby2016(self):
print("测试baby2016登录")
if __name__ == '__main__':
suite = unittest.TestSuite()
testcases = unittest.defaultTestLoader.discover(start_dir=os.getcwd(), pattern='*.py')
suite.addTests(testcases)
unittest.main(defaultTest='suite', verbosity=2)
执行结果:
$ python pls_login.py
test_01_laobai (pls_login.PlsLogin) ... 测试老百登录
ok
test_02_nichengwe (pls_login.PlsLogin) ... 测试nichengwe登录
ok
test_03_baby2016 (pls_login.PlsLogin) ... 测试baby2016登录
ok
test_01_laobai (pls_register.PlsRegister) ... 测试注册账号-老百
ok
test_02_nichengwe (pls_register.PlsRegister) ... 测试注册账号-nichengwe
ok
test_03_baby2016 (pls_register.PlsRegister) ... 测试注册账号-baby2016
ok
----------------------------------------------------------------------
Ran 6 tests in 0.001s
OK
其中,os.getcwd()
是获取当前目录
TestLoader
可以通过TestLoader
测试装载器去装载测试用例所在的类
import unittest
import pls_register
import pls_login
if __name__ == '__main__':
loader = unittest.TestLoader()
suite1 = loader.loadTestsFromTestCase(pls_register.PlsRegister)
suite2 = loader.loadTestsFromTestCase(pls_login.PlsLogin)
suite = unittest.TestSuite([suite1, suite2])
unittest.TextTestRunner(verbosity=2).run(suite)
运行结果:
测试注册账号-老百
测试注册账号-nichengwe
测试注册账号-baby2016
测试老百登录
测试nichengwe登录
测试baby2016登录
test_01_laobai (pls_register.PlsRegister) ... ok
test_02_nichengwe (pls_register.PlsRegister) ... ok
test_03_baby2016 (pls_register.PlsRegister) ... ok
test_01_laobai (pls_login.PlsLogin) ... ok
test_02_nichengwe (pls_login.PlsLogin) ... ok
test_03_baby2016 (pls_login.PlsLogin) ... ok
----------------------------------------------------------------------
Ran 6 tests in 0.002s
OK
Process finished with exit code 0
TestFixture测试夹具
对一个测试用例环境的搭建和销毁,是一个fixture
,通过覆盖TestCase
的setUp()
和tearDown()
方法来实现。根据应用范围,有如下4个:
setUp
:每运行一个用例前都会执行一次;
tearDown
:每运行一个用例或都会执行一次;
setUpClass
:在测试用例类执行开始前执行,只执行一次;
tearDownClass
:在测试用例类执行结束后执行,只执行一次;
setUpModule
:在模块测试用例模块执行开始前执行,只执行一次;
tearDownModule
:在模块测试用例模块执行结束后执行,只执行一次;
import unittest
def setUpModule():
print("模块级的夹具开始前")
def tearDownModule():
print("模块级的夹具结束后")
class PlsLogin(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
print("setUpClass:在当前类中用例执行之前只执行一次")
def setUp(self) -> None:
print("\nsetUp:在测试用例之前的准备工作")
# 测试用例01-测试老百登录
def test_01_laobai(self):
print("测试老百登录")
# 测试用例02-测试nichengwe登录
def test_02_nichengwe(self):
print("测试nichengwe登录")
# 测试用例02-测试baby2016登录
def test_03_baby2016(self):
print("测试baby2016登录")
def tearDown(self) -> None:
print("tearDown:在每个用例执行完成之后执行一次")
@classmethod
def tearDownClass(cls) -> None:
print("tearDownClass:在每个类执行完之后执行一次")
if __name__ == '__main__':
suite = unittest.TestSuite()
testcases = [PlsLogin('test_03_baby2016'),PlsLogin('test_01_laobai'),PlsLogin('test_02_nichengwe')]
suite.addTests(testcases)
unittest.main(defaultTest='suite', verbosity=2)
执行结果:
$ python pls_login.py
模块级的夹具开始前
setUpClass:在当前类中用例执行之前只执行一次
test_03_baby2016 (__main__.PlsLogin) ...
setUp:在测试用例之前的准备工作
测试baby2016登录
tearDown:在每个用例执行完成之后执行一次
ok
test_01_laobai (__main__.PlsLogin) ...
setUp:在测试用例之前的准备工作
测试老百登录
tearDown:在每个用例执行完成之后执行一次
ok
test_02_nichengwe (__main__.PlsLogin) ...
setUp:在测试用例之前的准备工作
测试nichengwe登录
tearDown:在每个用例执行完成之后执行一次
ok
tearDownClass:在每个类执行完之后执行一次
模块级的夹具结束后
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
注:针对模块的夹具很少使用,之后的例子中将不在设计Module夹具。
针对一个项目,测试用例会很多(写在多个py文件中,每个py文件中有多个用例),可以将夹具提取出来,不用每个py文件中都写。
新建pls_unit.py
import unittest
class PlsUnit(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
print("setUpClass:在当前类中用例执行之前只执行一次")
def setUp(self) -> None:
print("\nsetUp:在测试用例之前的准备工作")
def tearDown(self) -> None:
print("tearDown:在每个用例执行完成之后执行一次")
@classmethod
def tearDownClass(cls) -> None:
print("tearDownClass:在每个类执行完之后执行一次")
这样测试用例的py中就不用写夹具了,导入pls_unit
即可
修改pls_register.py
如下:
import unittest
import pls_unit
class PlsRegister(pls_unit.PlsUnit):
# 测试用例01-测试注册账号-老百
def test_01_laobai(self):
print("测试注册账号-老百")
# 测试用例02-测试注册账号-nichengwe
def test_02_nichengwe(self):
print("测试注册账号-nichengwe")
# 测试用例03-测试注册账号-baby2016
def test_03_baby2016(self):
print("测试注册账号-baby2016")
修改pls_login.py
如下:
import unittest
import pls_unit
class PlsLogin(pls_unit.PlsUnit):
# 测试用例01-测试老百登录
def test_01_laobai(self):
print("测试老百登录")
# 测试用例02-测试nichengwe登录
def test_02_nichengwe(self):
print("测试nichengwe登录")
# 测试用例02-测试baby2016登录
def test_03_baby2016(self):
print("测试baby2016登录")
新建main.py
import os
import unittest
if __name__ == '__main__':
suite = unittest.TestSuite()
testcases = unittest.defaultTestLoader.discover(os.getcwd(), "*.py")
suite.addTests(testcases)
unittest.TextTestRunner(verbosity=2).run(suite)
运行main.py结果如下:
test_01_laobai (pls_register.PlsRegister) ... ok
test_02_nichengwe (pls_register.PlsRegister) ... ok
test_03_baby2016 (pls_register.PlsRegister) ... ok
test_01_laobai (pls_login.PlsLogin) ... ok
test_02_nichengwe (pls_login.PlsLogin) ... ok
test_03_baby2016 (pls_login.PlsLogin) ... ok
----------------------------------------------------------------------
Ran 6 tests in 0.001s
OK
测试注册账号-老百
测试注册账号-nichengwe
测试注册账号-baby2016
setUpClass:在当前类中用例执行之前只执行一次
setUp:在测试用例之前的准备工作
测试老百登录
tearDown:在每个用例执行完成之后执行一次
setUp:在测试用例之前的准备工作
测试nichengwe登录
tearDown:在每个用例执行完成之后执行一次
setUp:在测试用例之前的准备工作
测试baby2016登录
tearDown:在每个用例执行完成之后执行一次
tearDownClass:在每个类执行完之后执行一次
Process finished with exit code 0
TestRunner测试运行器
运行器,前面已经讲了,一般通过runner
来调用suite去执行,unittest
框架的TextTestRunner()
类,通过该类下面的run()
方法运行suite
所组装的测试用例,入参为suite
测试套件
import os
import unittest
if __name__ == '__main__':
suite = unittest.TestSuite()
testcases = unittest.defaultTestLoader.discover(os.getcwd(), "*.py")
suite.addTests(testcases)
unittest.TextTestRunner(verbosity=2).run(suite)
mport unittest
import pls_register
import pls_login
if __name__ == '__main__':
loader = unittest.TestLoader()
suite1 = loader.loadTestsFromTestCase(pls_register.PlsRegister)
suite2 = loader.loadTestsFromTestCase(pls_login.PlsLogin)
suite = unittest.TestSuite([suite1, suite2])
unittest.TextTestRunner(verbosity=2).run(suite)
常用方法
跳过测试用例
skip装饰器
@unittest.skip(reason)
:无条件跳过装饰的测试用例,reason
参数是跳过用例的原因;import unittest class PlsRegister(unittest.TestCase): # 测试用例01-测试注册账号-老百 @unittest.skip("老百是系统初始化账号无需注册") def test_01_laobai(self): print("测试注册账号-老百") # 测试用例02-测试注册账号-nichengwe def test_02_nichengwe(self): print("测试注册账号-nichengwe") # 测试用例03-测试注册账号-baby2016 def test_03_baby2016(self): print("测试注册账号-baby2016") if __name__ == '__main__': suite = unittest.TestSuite() testcases = [PlsRegister('test_02_nichengwe'), PlsRegister('test_01_laobai'), PlsRegister('test_03_baby2016')] suite.addTests(testcases) unittest.main(defaultTest='suite', verbosity=2)
执行结果:
$ python pls_register.py test_02_nichengwe (__main__.PlsRegister) ... 测试注册账号-nichengwe ok test_01_laobai (__main__.PlsRegister) ... skipped '老百是系统初始化账号无需注册' test_03_baby2016 (__main__.PlsRegister) ... 测试注册账号-baby2016 ok ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK (skipped=1)
@unittest.skipIf(condition, reason)
:condition
条件为真时,跳过装饰的测试用例,reason
参数是跳过用例的原因;import unittest class PlsRegister(unittest.TestCase): age = 17 # 测试用例01-测试注册账号-老百 @unittest.skip("老百是系统初始化账号无需注册") def test_01_laobai(self): print("测试注册账号-老百") # 测试用例02-测试注册账号-nichengwe @unittest.skipIf(age <= 18, "未成年人不能注册") def test_02_nichengwe(self): print("测试注册账号-nichengwe") # 测试用例03-测试注册账号-baby2016 def test_03_baby2016(self): print("测试注册账号-baby2016") if __name__ == '__main__': suite = unittest.TestSuite() testcases = [PlsRegister('test_02_nichengwe'), PlsRegister('test_01_laobai'), PlsRegister('test_03_baby2016')] suite.addTests(testcases) unittest.main(defaultTest='suite', verbosity=2)
执行结果:
$ python pls_register.py test_02_nichengwe (__main__.PlsRegister) ... skipped '未成年人不能注册' test_01_laobai (__main__.PlsRegister) ... skipped '老百是系统初始化账号无需注册' test_03_baby2016 (__main__.PlsRegister) ... 测试注册账号-baby2016 ok ---------------------------------------------------------------------- Ran 3 tests in 0.001s OK (skipped=2)
@unittest.skipUnless(condition, reason)
:condition
条件为假时,跳过装饰的测试用例,reason
参数是跳过用例的原因;import unittest class PlsRegister(unittest.TestCase): age = 17 # 测试用例01-测试注册账号-老百 @unittest.skip("老百是系统初始化账号无需注册") def test_01_laobai(self): print("测试注册账号-老百") # 测试用例02-测试注册账号-nichengwe @unittest.skipIf(age <= 18, "未成年人不能注册") def test_02_nichengwe(self): print("测试注册账号-nichengwe") # 测试用例03-测试注册账号-baby2016 @unittest.skipUnless(age <= 16 or age >= 18, "只有17岁的无法注册") def test_03_baby2016(self): print("测试注册账号-baby2016") if __name__ == '__main__': suite = unittest.TestSuite() testcases = [PlsRegister('test_02_nichengwe'), PlsRegister('test_01_laobai'), PlsRegister('test_03_baby2016')] suite.addTests(testcases) unittest.main(defaultTest='suite', verbosity=2)
执行结果:
$ python pls_register.py test_02_nichengwe (__main__.PlsRegister) ... skipped '未成年人不能注册' test_01_laobai (__main__.PlsRegister) ... skipped '老百是系统初始化账号无需注册' test_03_baby2016 (__main__.PlsRegister) ... skipped '只有17岁的无法注册' ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK (skipped=3)
TestCase.skipTest()方法
可以在需要跳过的用例中增加self.skipTest()
来跳过当前用例,括号中填入跳过原因
import unittest
class PlsRegister(unittest.TestCase):
age = 17
# 测试用例01-测试注册账号-老百
def test_01_laobai(self):
self.skipTest("跳过此用例。。。")
print("测试注册账号-老百")
# 测试用例02-测试注册账号-nichengwe
def test_02_nichengwe(self):
print("测试注册账号-nichengwe")
# 测试用例03-测试注册账号-baby2016
def test_03_baby2016(self):
print("测试注册账号-baby2016")
if __name__ == '__main__':
suite = unittest.TestSuite()
testcases = [PlsRegister('test_02_nichengwe'), PlsRegister('test_01_laobai'), PlsRegister('test_03_baby2016')]
suite.addTests(testcases)
unittest.main(defaultTest='suite', verbosity=2)
执行结果:
$ python pls_register.py
test_02_nichengwe (__main__.PlsRegister) ... 测试注册账号-nichengwe
ok
test_01_laobai (__main__.PlsRegister) ... skipped '跳过此用例。。。'
test_03_baby2016 (__main__.PlsRegister) ... 测试注册账号-baby2016
ok
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK (skipped=1)
命令行执行测试
指定用例
指定测试模块
$ python -m unittest pls_register pls_login s测试注册账号-nichengwe .测试注册账号-baby2016 .测试老百登录 .测试nichengwe登录 .测试baby2016登录 . ---------------------------------------------------------------------- Ran 6 tests in 0.000s OK (skipped=1)
指定测试类
$ python -m unittest pls_register.PlsRegister pls_login.PlsLogin s测试注册账号-nichengwe .测试注册账号-baby2016 .测试老百登录 .测试nichengwe登录 .测试baby2016登录 . ---------------------------------------------------------------------- Ran 6 tests in 0.000s OK (skipped=1)
指定测试方法(用例)
$ python -m unittest pls_register.PlsRegister.test_02_nichengwe 测试注册账号-nichengwe . ---------------------------------------------------------------------- Ran 1 test in 0.000s OK
自动发现用例
前提条件:由于unittest
自动发现测试用例的文件模板是test*.py
,所以,将pls_register.py
修改为test_pls_register.py
,将pls_login.py
改为test_pls_login.py
自动搜索当前目录
$ python -m unittest 测试老百登录 .测试nichengwe登录 .测试baby2016登录 .s测试注册账号-nichengwe .测试注册账号-baby2016 . ---------------------------------------------------------------------- Ran 6 tests in 0.000s OK (skipped=1)
$ python -m unittest discover 测试老百登录 .测试nichengwe登录 .测试baby2016登录 .s测试注册账号-nichengwe .测试注册账号-baby2016 . ---------------------------------------------------------------------- Ran 6 tests in 0.000s OK (skipped=1)
自动搜索指定目录及文件的名称模式
$ python -m unittest discover -s /Users/laobai/workspaces/testdemo01/unittestdemo -p "test_*.py" 测试老百登录 .测试nichengwe登录 .测试baby2016登录 .s测试注册账号-nichengwe .测试注册账号-baby2016 . ---------------------------------------------------------------------- Ran 6 tests in 0.000s OK (skipped=1)