目录结构
一、新增测试用例管理
二、用例公共部分的合并
三、用例执行的顺序
四、用例综合框架的管理
五、跳过测试和设置预期失败
一、新增测试用例管理
在前文UnitTest单元测试概述&案例实践是针对单个add方法进行单元测试,本文则是针对需要多个方法进行单元测试的场景。
实践案例-流程:
1)在A文件中创建一个Math类,在Math类中定义2个方法(add和sub方法)
2)在B文件中导入A文件中的所有方法,然后分别创建2个测试类(Test_add和Test_sub),并在这两个类中定义各自的测试方法
3)构造测试集,分别将2个测试类中测试方法加载到测试集中
4)执行单元测试用例
编写代码:
calculator2.py
class Math:
def __init__(self,a,b): # 初始化
self.a = int(a)
self.b = int(b)
def add(self):
return self.a+self.b
def sub(self):
return self.a-self.b
test_Math2.py
from calculator2 import Math
import unittest
class Test_add(unittest.TestCase):
def setUp(self):
print("--Starting Test--")
def test_add1(self):
j = Math(5,5)
self.assertEqual(j.add(),10)
def test_add2(self):
j = Math(10,20)
self.assertEqual(j.add(),30)
def tearDown(self):
print("--End--")
class Test_sub(unittest.TestCase):
def setUp(self):
print("--Starting Test--")
def test_sub1(self):
i = Math(8,8)
self.assertEqual(i.sub(),0)
def test_sub2(self):
i = Math(5,3)
self.assertEqual(i.sub(),2)
def tearDown(self):
print("--End--")
if __name__=='__main__':
suite = unittest.TestSuite()
suite.addTest(Test_add("test_add1"))
suite.addTest(Test_add("test_add2"))
suite.addTest(Test_sub("test_sub1"))
suite.addTest(Test_sub("test_sub2"))
runner = unittest.TextTestRunner()
runner.run(suite)
执行结果:
Ran 4 tests in 0.016s
OK
--Starting Test--
--End--
--Starting Test--
--End--
--Starting Test--
--End--
--Starting Test--
--End--
二、用例公共部分的合并
以上代码中的每个测试类都有setUp()和tearDown()方法,且两个方法都是一样的,用于打印测试开始和结束的提示语.可以考虑将其合并在一个类中,作为每个测试类共同的父类来继承,就不需要每次单独去写。
from calculator2 import Math
import unittest
class Test_StartEnd(unittest.TestCase):
def setUp(self):
print("--Test Start--")
def tearDown(self):
print("--Test End--")
class Test_add(Test_StartEnd):
def test_add(self):
j = Math(5,5)
self.assertEqual(j.add(),10)
class Test_sub(Test_StartEnd):
def test_sub(self):
i = Math(3,2)
self.assertEqual(i.sub(),1)
# 执行所有的2个测试用例
if __name__=='__main__':
unittest.main()
执行结果:
Ran 2 tests in 0.016s
OK
--Test Start--
--Test End--
--Test Start--
--Test End--
三、用例执行的顺序
以下代码,在不作代码调控设置的前提下,执行过程是否是与常规认为的自上而下顺序执行呢?(C-->B-->A-->D ?)
import unittest
class Test_StartEnd(unittest.TestCase):
def setUp(self):
print("--Test Start--")
def tearDown(self):
print("--Test End--")
class Test2(Test_StartEnd):
def test_c(self):
print("C")
def test_b(self):
print("B")
class Test1(Test_StartEnd):
def test_a(self):
print("A")
class Test3(Test_StartEnd):
def test_d(self):
print("D")
实际执行结果:
--Test Start--
A
--Test End--
--Test Start--
B
--Test End--
--Test Start--
C
--Test End--
--Test Start--
D
--Test End--
从执行结果中,可以分析出:
(对于PyCharm默认的runner为Unittests的情况)
1)代码执行顺序的优先级:测试类>>测试方法。即先根据测试类排序区分,然后再分别定位到每个测试类的不同测试方法的排序
2)测试类or测试方法:根据字母or数字从小到大排序执行,如1-->2-->3、a-->b-->c-->d
现在通过代码中调控按照设置的顺序来执行测试用例:
import unittest
class Test_StartEnd(unittest.TestCase):
def setUp(self):
print("--Test Start--")
def tearDown(self):
print("--Test End--")
class Test2(Test_StartEnd):
def test_c(self):
print("C")
def test_b(self):
print("B")
class Test1(Test_StartEnd):
def test_a(self):
print("A")
class Test3(Test_StartEnd):
def test_d(self):
print("D")
if __name__=='__main__':
suite = unittest.TestSuite()
suite.addTest(Test3("test_d"))
suite.addTest(Test2("test_c"))
suite.addTest(Test1("test_a"))
suite.addTest(Test2("test_b"))
runner = unittest.TextTestRunner()
runner.run(suite)
执行结果:
- 若按PyCharm默认的runner为Unittests执行,则可能依然还是没有按照设定的顺序执行
- 若修改PyCharm的默认的runner为py.test执行,则PyCharm中可按照测试类自上而下执行用例(具体修改方法,可参看设置PyCharm根据测试类自上而下顺序执行代码)
- 若以cmd命令行执行,则执行效果可按照程序设定控制的顺序执行输出
四、用例综合框架的管理
以上测试用例及用例执行都是卸载一个文件中,当用例数量不断增加,用例的执行与管理会变得非常冗杂和低效率,因此需要对用例根据具体的功能模块来使用单独的模块进行管理。
案例:新建一个文件目录Test_Project
,其下包含4个python文件进行用例的管理和执行分工
① StartEnd.py ==>setUp与tearDown的管理
② calculator.py ==>加减法运算方法的实现
③ test_add.py ==>加法测试模块
④ test_sub.py ==>减法测试模块
⑤ runtest.py ==>用例执行管理模块
① StartEnd.py
import unittest
class setUp_tearDown(unittest.TestCase):
def setUp(self):
print("--Start Test--")
def tearDown(self):
print("--Test End--")
② calculator.py
class Math:
def __init__(self,a,b):
self.a = int(a)
self.b = int(b)
def add(self):
return self.a+self.b
def sub(self):
return self.a-self.b
③ test_add.py
from calculator import *
from StartEnd import *
class Test_Add(setUp_tearDown):
def test_add1(self):
i = Math(5,5)
self.assertEqual(i.add(),10)
def test_add2(self):
i = Math(1,2)
self.assertEqual(i.add(),3)
④ test_sub.py
from calculator import *
from StartEnd import *
class Test_Sub(setUp_tearDown):
def test_sub1(self):
j = Math(6,6)
self.assertEqual(j.sub(),0)
def test_sub2(self):
j = Math(7,6)
self.assertEqual(j.sub(),1)
⑤ runtest.py
import unittest
# 被测脚本的路径
test_dir = './' # 此时表示当前目录
# 使用discover可以一次调用多个脚本;pattern设置脚本名称的匹配规则
discover = unittest.defaultTestLoader.discover(test_dir,pattern='test*.py')
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(discover)
在以上第⑤个python文件runtest.py
执行代码,调用其他模块,执行的结果为:
五、跳过测试和设置预期失败
① @unittest.skip("reason") ==>直接跳过测试
② @unittest.skipIf(condition,"reason") ==>条件为真,跳过测试
③ @unittest.skipUnless(condition,"reason") ==>条件为假,跳过测试
④ @unittest.expectedFailure ==>设置预期为失败
@unittest.skip("reason")
import unittest
class Test_StartEnd(unittest.TestCase):
def setUp(self):
print("--Test Start--")
def tearDown(self):
print("--Test End--")
@unittest.skip("skip Test2")
class Test2(Test_StartEnd):
def test_c(self):
print("C")
def test_b(self):
print("B")
class Test1(Test_StartEnd):
def test_a(self):
print("A")
if __name__ == '__main__':
unittest.main()
执行结果:
直接跳过测试类@unittest.skipIf(condition,"reason")
import unittest
class Test_StartEnd(unittest.TestCase):
def setUp(self):
print("--Test Start--")
def tearDown(self):
print("--Test End--")
class Test2(Test_StartEnd):
def test_c(self):
print("C")
@unittest.skipIf(1,"skip test_b")
def test_b(self):
print("B")
class Test1(Test_StartEnd):
def test_a(self):
print("A")
if __name__ == '__main__':
unittest.main()
执行结果:
判断条件为真,跳过测试方法@unittest.skipUnless(condition,"reason")
import unittest
class Test_StartEnd(unittest.TestCase):
def setUp(self):
print("--Test Start--")
def tearDown(self):
print("--Test End--")
class Test2(Test_StartEnd):
@unittest.skipUnless(1>2,"skip test_c")
def test_c(self):
print("C")
def test_b(self):
print("B")
class Test1(Test_StartEnd):
def test_a(self):
print("A")
if __name__ == '__main__':
unittest.main()
执行结果:
判断条件为假,跳过测试方法@unittest.expectedFailure
import unittest
class Test_StartEnd(unittest.TestCase):
def setUp(self):
print("--Test Start--")
def tearDown(self):
print("--Test End--")
class Test2(Test_StartEnd):
def test_c(self):
print("C")
def test_b(self):
print("B")
class Test1(Test_StartEnd):
@unittest.expectedFailure
def test_a(self):
print("A")
if __name__ == '__main__':
unittest.main()
执行结果:
设置预期失败【附】
⑤ @classmethod ==>实现对测试类运行前&后的处理
import unittest
class Test_StartEnd(unittest.TestCase):
def setUp(self): # 实现对每个测试方法执行前的处理
print("--Test Start--")
def tearDown(self): # 实现对每个测试方法执行后的处理
print("--Test End--")
class Test2(Test_StartEnd):
def test_c(self):
print("C")
def test_b(self):
print("B")
class Test1(Test_StartEnd):
@classmethod
def setUpClass(cls): # 实现对测试类Test1运行前的处理
print("Class module start test>>>>>>>>>")
@classmethod
def tearDownClass(cls): # 实现对测试Test1运行后的处理
print("Class module test end>>>>>>>>>>>")
def test_a(self):
print("A")
if __name__ == '__main__':
unittest.main()
执行结果:
测试类、测试方法-前&后的处理对比
网友评论