前言
虽然前面可以通过参数化的形式减少一个测试类的用例设计,直接通过参数化将数据传入到一个或两个测试用例中即可完成对应业务的相关数据测试。但是问题又来了:
我们知道测试用例的执行顺序是根据测试用例名称顺序执行的,在不改变用例名称的情况下,我们怎么来控制用例执行的顺序呢?
一个测试文件,我们直接执行该文件即可,但如果有多个测试文件,怎么进行组织,总不能一个个文件执行吧?
那么,如果需要解决以上两个问题,必然需要能够自由组织测试用例,组织测试用例必然需要引用到unittest框架中的测试套件(Test Suite)。
测试套件
对一个功能的验证往往是需要很多多测试用例,可以把测试用例集合在一起执行,这就产生了测试套件TestSuite 的概念,它是用来组装单个测试用例,规定用例的执行的顺序,而且TestSuite也可以嵌套TestSuite。
那么加载测试用例到套件中具体方法是哪些呢?
第一种方法:
可以通过addTest() 、addTests()加载TestCase 到TestSuite 中,再返回一个TestSuite 实例。
addTest
(test):表示的是添加一个测试用例或者测试套件到套件中;
addTests
(tests):表示的是添加所有的测试用例是一个可迭代对象或者测试套件实例到测试套件中,这个等价于addTest方法实现每个元素的添加;
这两个方法的具体含义是根据官方给出的进行翻译而来的。
具体代码实例如下:
from CRMProject.Test_Object.Login_Test import LoginTest
import unittest
#通过python运行器运行执行指定的测试用例(可以通过套件运行器进行一起使用)
def test_all():
#创建一个套件对象
suite=unittest.TestSuite()
#runTest属性是基于Unittest框架的运行器运行的,而现在是TextTestRunner运行器运行,此时可以覆盖methodName属性
#可以指定任意的测试方法进行组合
suite.addTest(LoginTest("test_login_success"))
suite.addTest(LoginTest("test_login_fail_2"))
#传入的参数是可迭代对象,相当于下面代码完成一组用例的执行,上面相当于是一个用例一个用例进行添加到套件中
suite.addTests([LoginTest("test_login_success"),LoginTest("test_login_fail_2")])
# 声明运行器对象
runner=unittest.TextTestRunner()
runner.run(suite)
if __name__ == '__main__':
test_all()
从上述代码中可以分析发现,是将每个测试类中的测试用例所对应的方法一个一个进行添加到套件中;从而完成相关用例的组织操作,但是这样如果需要执行所有文件模块的测试用例的话,那太麻烦了,所以就存在后面的解决方案;
第二种方法:
可以通过测试用例类或者对应的模块进行加载到测试套件中进行批量执行;如果是通过具体测试用例类加载的话,则必须需要引用unittest框架中的测试加载器(即TestLoader对象),具体代码实例如下:
from CRMProject.Test_Object.Login_Test_2 import LoginTest2
#导入Login_Test_2模块
from CRMProject.Test_Object import Login_Test_2
import unittest
def test_all():
#创建一个套件对象
suite=unittest.TestSuite()
#先创建一个加载器对象
load=unittest.TestLoader()
#加载整个测试类,loadTestsFromTestCase会返回一个测试套件;其中传入的参数必须是测试类名
suite.addTest(load.loadTestsFromTestCase(LoginTest2))
#通过模块进行添加到测试套件中,其中传入的参数是对应模块的对象名
suite.addTest(load.loadTestsFromModule(Login_Test_2))
#如果需要通过FromName进行加载到测试套件的话,传入的参数类型是一个字符串
suite.addTest(load.loadTestsFromName("Login_Test_2.LoginTest2.test_succes_login_0_admin"))
runner=unittest.TextTestRunner()
runner.run(suite)
if __name__ == '__main__':
test_all()
第三种方法:
如果存在多个模块的话,则每个模块同样需要手动完成依次运行,也过于麻烦;于是unittest框架测试套件也考虑到这一点为我们提供了批量执行的套件对象;批量执行,避免后期多个测试模块的一个一个手动执行或者手动添加到测试套件;*.py所有的以py为后缀的文件进行执行python3.5版本以后,discover加载模块会根据你当前模块中的import与discover的第一个参数开始目录进行确定,如果当前开始目录与import的模块是正确的且存在的,则会自动将其加载到加载器中,最后将所有的模块中的用例全部生成套件最后依次运行;如果没有import的话,pattern可以定义部分模块,实现模糊匹配筛选执行。
代码实例如下:
from CRMProject.Test_Object.Login_Test import LoginTest
from CRMProject.Test_Object.Login_Test_1 import LoginTest1
from CRMProject.Test_Object.Login_Test_2 import LoginTest2
from CRMProject.Test_Object.Login_Test_3 import LoginTest3
from CRMProject.Test_Object import Login_Test_2
import unittest
def test_all():
#创建一个套件对象
suite=unittest.TestSuite()
load=unittest.TestLoader()
#此种方式相当于pattern会失效,因为将所有模块已经import了,可以将所有
#import的模块全部注释的话则pattern生效。
suite.addTest(load.discover("../Test_Object",pattern="*Test.py"))
runner=unittest.TextTestRunner()
runner.run(suite)
if __name__ == '__main__':
test_all()
注意:上述描述的含义区别,在python3.5版本以后,discover加载的模块如果import对应的模块是正确的,会将所有的模块自动加载到对应的套件中的;如果需要引用pattern参数的话,则可以不需要导入操作;
报告生成
前面提到过,unittest框架是没有内置报告生成的模块的话,那么如果需要生成报告则必然引用第三方模块:HTMLTestRunner模块;在这里需要一提的是pycharm现如今已经集成了python3的HTMLTestRunner模块的了,再也不需要自己下载HTMLTestRunner模块然后修改符合python3的语法操作了;
HTMLTestRunner模块分析源代码发现实际其底层就是基于unittest框架进行实现的,并且其中内置了HTMLTestRunner运行器,所以可以通过该运行器替代TextRunner运行器即可获取到对应的报告;
具体代码示例如下:
#-*- coding:utf-8 -*-#
#-------------------------------------------------------------------------
#ProjectName: Python2020
#FileName: Login_Test_Suite.py
#Author: mutou
#Date: 2020/6/26 16:06
#Description:测试套件的运行
#--------------------------------------------------------------------------
import unittest
import time
#导入报告模块
from HTMLTestRunner import HTMLTestRunner
#获取当前的项目根目录
from CRMProject.GETP_ATH import GETPATH
#构建报告所在的目录路径,便于代码移植不会出现报告路径错误情况发生
path=GETPATH+"\Main_Object\Report\\"
reportname=None
def test_choice():
#创建一个套件对象
suite=unittest.TestSuite()
load=unittest.TestLoader()
#此处没有from import 相关的模块,则patter生效只会进行加载
suite.addTest(load.discover("../Test_Object",pattern="*Test.py"))
#如果需要生成报告的话,就可以使用HTMLTestRunner运行器运行;
#小技巧:报告的名称问题:如果报告名固定的话,则每次运行报告都会将上一次的报告进行覆盖处理,所以不建议不固定名称
#报告名称一般都会使用当前项目的名称_当前运行的时间 例如:CRM系统执行报告_202006262140
#获取当前时间
get_time=time.strftime("%Y%m%d%H%M%S",time.localtime())
global path,reportname
reportname="CRM_系统执行报告_"+str(get_time)+".html"
path=path+reportname
with open(path,mode="w") as fp:
runner=HTMLTestRunner.HTMLTestRunner(fp,verbosity=2,title="CRM登陆用例执行报告",description="详细内容如下")
#因为HTMLTestRunner刚好会返回TestResult,其本身就是基于unittest框架的TestResult进行实现的,所以可以直接获取该对象
get_result=runner.run(suite)
return get_result
if __name__ == '__main__':
test_choice()
上述代码报告生成添加了获取本地时间,以至于每次运行测试用例后产生的报告不会将前面的报告进行覆盖操作,则后期可以实现报告的对比分析。
需要了解更多,或者问题咨询可添加下面微信号: