代码编写与用例组织
欢迎加入测试交流群:夜行者自动化测试(816489363)进行交流学习QAQ
–成都-阿木木
再使用unittest
编写你的测试代码时,测试类必须继承TestCase
或者FunctionTestCase
.
官网有一段组织测试用例的描述,为什么会衍生出setup/teardown/setUpClass/tearDownClass
,用比较直白的话来表述,就是我们不会在每一个test method中去实例化测试对象等公共操作,这些重复的操作会导致代码看起来很难看,所以提供了夹具test fixture来进行设置这一类需要在每个测试类或者测试方法前后进行环境初始化,或者环境清理的对象或公共操作。
当用例执行发现setup/setUpClass
方法执行失败时,不会再运行后面的test method
,当teardown/tearDownClass
执行失败时,test_method
方法仍然会运行。
一条测试用例是如何标记为失败呢?使用基类assert*()
提供的方法对于用例中的结果进行断言,如果断言失败,就会引发异常。也就是说unittest
框架通过识别异常将用例标记为fail。其他不属于assert
抛出的异常,都会被识别成ERROR。
#!/user/bin/env python
# -*- coding: utf-8 -*-
"""
------------------------------------
@Project : mysite
@Time : 2020/8/28 11:32
@Auth : chineseluo
@Email : 848257135@qq.com
@File : unittest_demo.py
@IDE : PyCharm
------------------------------------
"""
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
print("运行于测试方法前,主要用于环境初始化")
def tearDown(self):
print("运行于测试方法后,主要用户环境数据清理")
def test_upper(self):
print("this is a test_upper method")
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
print("this is a test_isupper method")
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
print("this is a test_split method")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
运行结果:
运行于测试方法前,主要用于环境初始化
this is a test_isupper method
运行于测试方法后,主要用户环境数据清理
运行于测试方法前,主要用于环境初始化
this is a test_split method
运行于测试方法后,主要用户环境数据清理
运行于测试方法前,主要用于环境初始化
this is a test_upper method
运行于测试方法后,主要用户环境数据清理
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
在下面的例子中修改test_upper方法中的self.assertEqual('foo'.upper(), 'FOO')
为self.assertEqual('foo'.upper(), 'FO')
,查看断言异常运行结果,可以看到FAILED(failures=1)
,属于unittest
可识别的断言异常。
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
print("运行于测试方法前,主要用于环境初始化")
def tearDown(self):
print("运行于测试方法后,主要用户环境数据清理")
def test_upper(self):
print("this is a test_upper method")
self.assertEqual('foo'.upper(), 'FO')
def test_isupper(self):
print("this is a test_isupper method")
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
print("this is a test_split method")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
运行结果为:
C:UsersluozhongwenAppDataLocalProgramsPythonPython38python.exe D:/TestScriptDir/python_web/mysite/unittest_demo.py
..F
======================================================================
FAIL: test_upper (__main__.TestStringMethods)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:/TestScriptDir/python_web/mysite/unittest_demo.py", line 26, in test_upper
self.assertEqual('foo'.upper(), 'FO')
AssertionError: 'FOO' != 'FO'
- FOO
? -
+ FO
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (failures=1)
运行于测试方法前,主要用于环境初始化
this is a test_isupper method
运行于测试方法后,主要用户环境数据清理
运行于测试方法前,主要用于环境初始化
this is a test_split method
运行于测试方法后,主要用户环境数据清理
运行于测试方法前,主要用于环境初始化
this is a test_upper method
运行于测试方法后,主要用户环境数据清理
Process finished with exit code 1
在下面的例子的test_isupper
中添加一个非断言异常,索引越界异常,查看运行结果,可以看到这是一个非assert的异常,被标记为了error
。
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
print("运行于测试方法前,主要用于环境初始化")
def tearDown(self):
print("运行于测试方法后,主要用户环境数据清理")
def test_upper(self):
print("this is a test_upper method")
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
print("this is a test_isupper method")
a = [1, 2, 3]
print(a[4])
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
print("this is a test_split method")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
结果为:
======================================================================
ERROR: test_isupper (__main__.TestStringMethods)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:/TestScriptDir/python_web/mysite/unittest_demo.py", line 31, in test_isupper
print(a[4])
IndexError: list index out of range
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (errors=1)
运行于测试方法前,主要用于环境初始化
this is a test_isupper method
运行于测试方法后,主要用户环境数据清理
运行于测试方法前,主要用于环境初始化
this is a test_split method
运行于测试方法后,主要用户环境数据清理
运行于测试方法前,主要用于环境初始化
this is a test_upper method
运行于测试方法后,主要用户环境数据清理
Process finished with exit code 1
执行用例:
unittest
框架建议在进行测试用例编写时,按照功能进行测试用例分组,unittest
提供了一种机制:测试套件,由unittest
的TestSuite
类表示。通常使用unittest.main()
,它会自动收集所有模块的测试用例并执行它们。
有时候我们需要自定义测试套件的构建,需要自己进行测试套的添加。
- 测试套可以放在相同的模块(例如:
unittest_demo.py
),针对当前测试模块,测试用例,测试方法 - 测试套也可以放在一个脚本的入口模块中,例如
run.py
中,进行各个测试模块中细分的方法的执行
放在相同脚本的当中:
#!/user/bin/env python
# -*- coding: utf-8 -*-
"""
------------------------------------
@Project : mysite
@Time : 2020/8/28 11:32
@Auth : chineseluo
@Email : 848257135@qq.com
@File : unittest_demo.py
@IDE : PyCharm
------------------------------------
"""
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
print("运行于测试方法前,主要用于环境初始化")
def tearDown(self):
print("运行于测试方法后,主要用户环境数据清理")
def test_upper(self):
print("this is a test_upper method")
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
print("this is a test_split method")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
def suite():
suite = unittest.TestSuite()
suite.addTest(TestStringMethods('test_upper'))
suite.addTest(TestStringMethods('test_isupper'))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
运行结果:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
运行于测试方法前,主要用于环境初始化
this is a test_upper method
运行于测试方法后,主要用户环境数据清理
运行于测试方法前,主要用于环境初始化
运行于测试方法后,主要用户环境数据清理
Process finished with exit code 0
放在不同的脚本中,通过导入需要进行自定义测试套件的模块下的测试类:
#!/user/bin/env python
# -*- coding: utf-8 -*-
"""
------------------------------------
@Project : mysite
@Time : 2020/8/28 11:32
@Auth : chineseluo
@Email : 848257135@qq.com
@File : unittest_demo.py
@IDE : PyCharm
------------------------------------
"""
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
print("运行于测试方法前,主要用于环境初始化")
def tearDown(self):
print("运行于测试方法后,主要用户环境数据清理")
def test_upper(self):
print("this is a test_upper method")
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
print("this is a test_split method")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
run.py
#!/user/bin/env python
# -*- coding: utf-8 -*-
"""
------------------------------------
@Project : mysite
@Time : 2020/8/31 9:29
@Auth : chineseluo
@Email : 848257135@qq.com
@File : run.py
@IDE : PyCharm
------------------------------------
"""
import unittest
from unittest_demo import TestStringMethods
def suite():
suite = unittest.TestSuite()
suite.addTest(TestStringMethods('test_upper'))
suite.addTest(TestStringMethods('test_isupper'))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())