Python+selenium+unittest单元测试框架
为什么要做单元测试
unittest是python的单元测试框架。是受测试框架JUnit 的启发,它提供了组织管理测试用例的功能,灵活的执行
测试用例,生成可视化测试报告的功能
注意:unittest自己本身没办法实现测试报告的生成,需要借助于插件来完成
单元测试之后,才是集成测试,单个单个的功能模块测试通过之后,才能把单个功能模块集成起来做集成测试,为
了从底层发现bug,单元测试时可以减少合成后出现的问题。
越早发现bug越好,这样可以早点发现问题,不然问题累计到后面,很可能会因为一个做错了而导致整个模块甚至
更大范围的推倒重来,对于时间和经费来说,是非常浪费的!
对于测试来说,单元测试就是为了执行用例,输入测试数据–输出测试结果
单元测试其实是开发自己完代码,自己进行测试,这一环节是使用测试代码来测自己的项目代码
不仅有unittest,还有pytest和rf,unittest、pytest都是聚焦于单元测试
rf其实才是对应我们系统测试阶段
unittest框架最核心的四个概念:
test case:就是我们的测试用例,unittest中提供了一个基本类TestCase,可以用来创建新的测试用例,一个TestCase的实例就是一个测试用例;unittest中测试用例方法都是以test开头的,且执行顺序会按照方法名的ASCII值排序。
test fixure:测试夹具,用于测试用例环境的搭建和销毁。即用例测试前准备环境的搭建(SetUp前置条件),测试后环境的还原(TearDown后置条件),比如测试前需要登录获取token等就是测试用例需要的环境,运行完后执行下一个用例前需要还原环境,以免影响下一条用例的测试结果。
test suite:测试套件,用来把需要一起执行的测试用例集中放到一块执行,相当于一个篮子。我们可以使用TestLoader来加载测试用例到测试套件中。
test runner:用来执行测试用例的,并返回测试用例的执行结果。它还可以用图形或者文本接口,把返回的测试结果更形象的展现出来,如:HTMLTestRunner。
unittest模块说明
- TestCase:一个TestCase的实例就是一个测试用例,是一个完整的测试流程,包括测试前准备环境的搭建(setUp),实现测试过程的代码(run),测试后环境的还原(tearDown).
- Test Suite:把多个测试用例集合在一起来执行。可以通过addTest加载TestCase到Test Suite(测试套件)中,从而返回一个TestSuite实例。
- Test Runner:测试的执行,通过TextTestRunner类提供的run()方法来执行Test Suite/TestCase。Test Runner可以使用图形界面,文本界面,或者返回一个特殊的值的方式来表示测试执行的结果。
- Test Fixture:对一个测试用例环境的初始化和清除。通过覆盖TestCase的setUp()和tearDown()方法来实现。tearDown()为下一个测试用例提供一个干净的环境。
unittest断言(assert断言)
所谓断言就是判断预期结果和实际结果是否一致
#判断相等
assertEqual
self.assertEqual(re_subtraction,4,msg="4不等于3") 第一个参数是实际结果,第二个是预期结果。msg指的是出现异常之后的提示信息
#两者不相等的时候通过。相等的时候不通过和assertEqual相反
assertNotEqual
初始化和清除
fixtures可以形象的看作是夹心饼干外层的两片饼干,这两片饼干就是setUp/tearDown,中间的心就是测试用例,除此以外
初始化和清除中是用来帮助我们测试用例准备执行时所需的测试数据的。比较理想的情况是,我们本次用户依赖的条件需要在setUp中添加,而用例执行时产生的数据需要在tearDown清除
举例子:发邮件 :用户必须登录,完成发邮件之后必须退出吧,在 setUp中就可以完成登录,发送邮件的测试用例执行结束后,tearDown中用户退出
用例的初始化和清除
#unittest内置框架,直接导入即可使用
import unittest
from day05.c1 import Count
#类里面就是我们的测试用例
class Count_test(unittest.TestCase): #要指定当前类中放的是测试用例,必须继承TestCase
#这个是用例的初始化和清除,它是作用于我们每一个用例,换句话说就是每条测试用例 执行之前都需要执行setUp,用户执行结果在执行一次tearDown
def setUp(self) -> None:
print("这是用例的初始化")
def tearDown(self) -> None:
print("这是用例的清除")
#测试用例是放在类中的方法,测试用例的开头必须是test
def test_add(self):
#调用加法
c1 = Count(3,5)
#接受返回值
re_add = c1.add()
#断言。判断是否等于8 实际结果和预期结果是否相等
print("我是加法")
self.assertEqual(re_add,8)
def test_subtraction(self):
s1 = Count(8,5)
#接受返回值
re_subtraction = s1.Subtraction()
print("我是减法")
self.assertEqual(re_subtraction,3,msg="4不等于3")
if __name__ == '__main__':
#unittest.main()会在当前模块查找以test开头的用例进行执行
unittest.main()
类和用例的初始化、清除
#unittest内置框架,直接导入即可使用
import unittest
from day05.c1 import Count
#类里面就是我们的测试用例
class Count_test(unittest.TestCase): #要指定当前类中放的是测试用例,必须继承TestCase
#类的初始化和清除,在进行用例执行之前执行setUpClass,当前类中的所有测试用例执行结束了才会执行tearDownClass,他们只会执行一次,优先级高于用例的清楚
@classmethod
def setUpClass(cls) -> None:
print("这是类的初始化")
@classmethod
def tearDownClass(cls) -> None:
print("这是类的清除")
#这个是用例的初始化和清除,它是作用于我们每一个用例,换句话说就是每条测试用例 执行之前都需要执行setUp,用户执行结果在执行一次tearDown
def setUp(self) -> None:
print("这是用例的初始化")
def tearDown(self) -> None:
print("这是用例的清除")
#测试用例是放在类中的方法,测试用例的开头必须是test
def test_add(self):
#调用加法
c1 = Count(3,5)
#接受返回值
re_add = c1.add()
#断言。判断是否等于8 实际结果和预期结果是否相等
print("我是加法")
self.assertEqual(re_add,8)
def test_subtraction(self):
s1 = Count(8,5)
#接受返回值
re_subtraction = s1.Subtraction()
print("我是减法")
self.assertEqual(re_subtraction,3,msg="4不等于3")
if __name__ == '__main__':
#unittest.main()会在当前模块查找以test开头的用例进行执行
unittest.main()
模块的初始化和清除 --> 类的初始化和清除 -->用例的初始化和清除
模块的初始化和清除 :会在我们当前模块开始执行之前会使用模块的初始化,在模块执行结束后会值模块的清除:
类的初始化和清除:会在执行完模块的初始化后执行类的初始化 ,在类的清除执行完成在执行模块的清除
用户的初始化和清除:用例初始化和清除在会对当前类中的每一个测试用例执行的时候进行执行
unittest测试套件常见的创建方法
方法1:可以通过addTest()加载TestCase到TestSuite中。用于少量的测试用例
suite.addTest(CountTest(‘test_add’))
suite.addTest(CountTest(‘test_subtraction’))
方法2:同时添加多个测试用例到套件之中
case = [CountTest(‘test_add’), CountTest(‘test_subtraction’)]
#将测试用例集合添加到套件中
suite.addTests(case)
方法3:模糊匹配给套件指定需要执行的测试用例
discover = unittest.defaultTestLoader.discover(start_dir=test_dir, pattern=‘tes*.py’)
方法4:添加整个类中的测试用例到套件中
#将CountTest类中所有用例添加到套件
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(CountTest))
unittest跳过用例不执行的常见方式
unittest提供了实现某些需求的装饰器,在执行测试用例时每个装饰前面加@符号。
@unittest.skip(reason)#无条件的跳过装饰的测试,说明跳过测试的原因
@unittest.skipIf(condition,reason)#跳过装饰的测试,如果条件为真。
@unittest.skipUnless(condition,reason)#跳过装饰的测试,除非条件为真。
@unittest.expectedFailure #如果断言失败,不计入执行case数目中
unittest借助于什么生成测试报告
HTMLTestRunner