测试 python测试-unittest 智汇君 2025-01-17 python测试-unittest https://www.bilibili.com/video/BV1bK3xzeEk2?spm_id_from=333.788.player.switch&vd_source=379b5659b7b00bb6caa4cadf9cc37ad6&p=20
测试框架 selenium、appium部署测试框架,是工具
UnitTest UnitTest、Testng等都是基于Junit的,所以:
历史悠久,其中各项概念、用法几乎成为标准
对新手友好,简单易学
有浓郁的Java风格,和python是不一样(缺点)
未提供插件接口,扩展不足(缺点)
pytest解决了unittest的一些问题
单元测试 :指的是在软件开发当中,对程序的最小单元(函数,方法)进行测试的过程。 unittest不仅可以用于单元测试,还可以用于自动化测试用例的开发和执行。组织执行自动化测试用例。并且提供一些丰富的断言方法,判断用例是否通过,最终能够生成测试报告。
基于Python的单元测试框架有哪些?
unittest:更简单,容易上手。
pytest:市场份额会更多
unittest和pytest的差异 默认测试用例的规则差异:
unittest 1.新建一个类,必须继承unittestTestCase(耦合) 2.测试用例必须以test开头。
pytest 1.测试文件必须test开头或test结尾。(非耦合) 2.测试类名必须Test开头 3.测试用例必须以test_开头 所有的开发:都逐渐遵循非耦合的方式,Sping,前后端分离的架构。
夹具的差异:
unittest setUp/tearDown 在每个用例的前后执行
setUpClass/tearDownClass 在每个类的前后执行。
setUpModule/tearDownModule 在每个模块的前后执行
pytest setup/teardown 在每个用例的前后执行
setup_class/teardown_class 在每个类的前后执行
setup_module/teardown_module 在每个模块的前后执行
断言差异:
unittest : selt.assertEqual()等(来自继承的父类)
pytest :python原生的assert(来自python原生assert)
失败用例重跑差异:
unitest:不支持
pytest:支持
参数化差异:
unitest:ddt(结合使用) pytest:@pytest.mark parametrize()(pytest的装饰器)
单元测试框架的作用 1.找到测试用例。根据他们的默认的测试用例的规则。(原理,底层。BAT。) 2.执行测试用例。 3.判断测试用例的结果。 4.生成测试报告。
unitest重要组件(源码阅读) TestCase测试用例: TestSuite测试套件:整理测试用例,形成一个集合。
TestFixtrue测试固件 TestL0ader测试加载器:加载测试用例套件或者测试用例。 TestRunner测试运行器:运行测试用例。
unittest.main()会去执行下面的初始化方法,因为导入import unittest时unitest文件最后一行是main = TestProgram:
1 2 3 4 5 def __init__ (self, module='__main__' , defaultTest=None , argv=None , testRunner=None , testLoader=loader.defaultTestLoader, exit=True , verbosity=1 , failfast=None , catchbreak=None , buffer=None , warnings=None , *, tb_locals=False , durations=None ):
1 2 3 4 5 6 7 8 9 10 11 module:测试用例所在的路径,__main__代表当前模块。(重要) defaultTest:默认的待测试的测试用例或者测试套件的名称。(重要) argV:接收外部传递给程序的参数 testRunner:测试运行器(重要) testLoader:测试加载器(重要) exit:是否在测试用例结束之后退出程序 verbosity:显示详细信息的程度。(重要) <0只显示用例总数以及全局执行结果 1默认值,显示用例总数以及全局执行结果外,还显示一个标记:.FE,S >=2显示用例总数以及全局执行结果外,显示详解结果 0 1 2常用
unittest运行测试用例 pycharm和vscode的运行代码时有点不同:
pycharm可能在代码有的函数或者类的地方可以直接执行(直接点击对应处按钮执行就是单元测试),其实还是执行的命令行命令
比如pycharm在执行unittest时,可能main里面包含启动执行测试用例的代码外还有其它代码,但是其它的代码不会执行(pytest里有个-s参数),其它还是等同于在命令行执行python -m unittest
unittest的运行方式有两种:
命令行的运行方式。(unittest默认的执行方式) python -m 就是以命令行的方式运行代码
1 2 3 4 5 6 7 8 import unittestclass TestApi (unittest.TestCase): def test_mashang (self ): print ("码尚教育软件测试" ) def test_baili (self ): print ("码尚百里" )
运行某一个类的所有测试用例 1 2 3 4 5 6 7 8 D:\code \TEST \UnitTest \src >python -m unittest test_run.TestApi 码尚百里 .码尚教育软件测试 . ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
运行某一个类的一个测试用例 1 2 3 4 5 6 7 D:\code \TEST \UnitTest \src >python -m unittest test_run.TestApi.test_baili 码尚百里 . ---------------------------------------------------------------------- Ran 1 test in 0.000s OK
运行某一个模块的所有测试用例 1 2 3 4 5 6 7 8 D:\code \TEST \UnitTest \src >python -m unittest test_run.py 码尚百里 .码尚教育软件测试 . ---------------------------------------------------------------------- Ran 2 tests in 0.001s OK
-v python -m unittest -v以更加详细的方式展示运行结果(pytest里也有)
-k 通配符匹配用例
python -m unittest test_api.py -k *_baili
以main的方式运行 在vscode中,下面main中的print可以正常打印。但是pycharm的话正常文件右键,或者点击run按钮会转换成python -m unittest命令,所以不会执行。可以在run按钮处添加python以main方式执行,然后正常点击run按钮就可以了。这时不要右键运行因为还是转换成python -m unittest
1 2 3 4 5 6 7 8 9 10 11 12 import unittestclass TestApi (unittest.TestCase): def test_mashang (self ): print ("码尚教育软件测试" ) def test_baili (self ): print ("码尚百里" ) if __name__ == "__main__" : print ("----d----" ) unittest.main()
unittest运行结果 .代表成功。
如果加了-V,那么.会变成OK
F代表用例执行失败。
E:出错。有异常抛出。
S:代表用例被跳过
1 2 3 4 5 6 7 8 9 10 11 import unittestclass TestApi (unittest.TestCase): def test_fun1 (self ): print ("success" ) def test_fun2 (self ): self .assertTrue(False ) def test_fun3 (self ): raise Exception("异常" )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 D:\code \TEST \UnitTest \src >python -m unittest test_result.py -k *fun * success .FE ====================================================================== ERROR : test_fun3 (test_result.TestApi.test_fun3 )---------------------------------------------------------------------- Traceback (most recent call last ): File "D :\code \TEST \UnitTest \src \test_result.py ", line 11, in test_fun3 raise Exception ("异常") Exception : 异常====================================================================== FAIL : test_fun2 (test_result.TestApi.test_fun2 )---------------------------------------------------------------------- Traceback (most recent call last ): File "D :\code \TEST \UnitTest \src \test_result.py ", line 8, in test_fun2 self.assertTrue (False ) AssertionError : False is not true ---------------------------------------------------------------------- Ran 3 tests in 0.001s FAILED (failures =1, errors =1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 D:\code \TEST \UnitTest \src >python -m unittest test_result.py -k *fun * -v test_fun1 (test_result.TestApi.test_fun1 ) ... success ok test_fun2 (test_result.TestApi.test_fun2 ) ... FAIL test_fun3 (test_result.TestApi.test_fun3 ) ... ERROR ====================================================================== ERROR : test_fun3 (test_result.TestApi.test_fun3 )---------------------------------------------------------------------- Traceback (most recent call last ): File "D :\code \TEST \UnitTest \src \test_result.py ", line 11, in test_fun3 raise Exception ("异常") Exception : 异常====================================================================== FAIL : test_fun2 (test_result.TestApi.test_fun2 )---------------------------------------------------------------------- Traceback (most recent call last ): File "D :\code \TEST \UnitTest \src \test_result.py ", line 8, in test_fun2 self.assertTrue (False ) AssertionError : False is not true ---------------------------------------------------------------------- Ran 3 tests in 0.002s FAILED (failures =1, errors =1)
unittest测试用例执行顺序 ord()是python的内置函数,作用是返回ASClI码。 根据ASCII的大小排序来执行测试用例,也就是test_后面的字符一个一个排序(也可以根据这个规则实现用例的执行顺序)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import unittestclass TestApi (unittest.TestCase): def test_00_xxx (self ): print ("00" ) def test_01_xxx (self ): print ("01" ) def test_02_xxx (self ): print ("02" ) def test_10_xxx (self ): print ("10" ) def test_99_xxx (self ): print ("99" )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 D:\code \TEST \UnitTest \src >python -m unittest test_run_order.py -v test_00_xxx (test_run_order.TestApi.test_00_xxx ) ... 00ok test_01_xxx (test_run_order.TestApi.test_01_xxx ) ... 01ok test_02_xxx (test_run_order.TestApi.test_02_xxx ) ... 02ok test_10_xxx (test_run_order.TestApi.test_10_xxx ) ... 10ok test_99_xxx (test_run_order.TestApi.test_99_xxx ) ... 99ok ---------------------------------------------------------------------- Ran 5 tests in 0.001s OK
多种unitttests的加载方式和运行测试用例方式 测试套件TestSuite 在一个文件里跑其它文件里的测试用例
当你使用 @ddt.ddt和 @ddt.data装饰器时不能通过下面的方式添加(遇到了再解决呗)
addTest 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import unittestimport ddtfrom HtmlTestRunner import HTMLTestRunnerdef add (a,b ): return a+b @ddt.ddt class MyTestCase (unittest.TestCase): @ddt.data( (1 ,1 ,2 ), (1 ,2 ,3 ), (5 ,-1 ,4 ) ) @ddt.unpack def test_bf (self,a,b,c ): result = add(a,b) self .assertEqual(result,c) @unittest.skip("skip" ) def test_skip (self ): pass @unittest.expectedFailure def test_xfail (self ): pass if __name__ == "__main__" : """ output=''./reports/"测试报告存放路径 report_title=None 测试报告标题 combine_reports=False合井报告到同一个文件 open_in_browser=False 自动打开报告Ttemplate=None自定义模板位置 """ report_argv = { "combine_reports" :True , "output" :'./../reports/' , "report_title" :"first_report" , "open_in_browser" :True } unittest.main(testRunner=HTMLTestRunner(**report_argv))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import unittestclass TestApi (unittest.TestCase): def test_00_xxx (self ): print ("00" ) def test_01_xxx (self ): print ("01" ) def test_02_xxx (self ): print ("02" ) def test_10_xxx (self ): print ("10" ) def test_99_xxx (self ): print ("99" )
1 2 3 4 5 6 7 8 9 10 11 12 import unittestfrom test_run_order import TestApifrom learn_ddt import MyTestCaseif __name__ == "__main__" : suite = unittest.TestSuite() suite.addTest(TestApi('test_01_xxx' )) suite.addTest(MyTestCase('test_bf' )) unittest.main(defaultTest='suite' )
addTests 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import unittestfrom test_run_order import TestApifrom learn_ddt import MyTestCaseif __name__ == "__main__" : suite = unittest.TestSuite() testcases = [TestApi('test_01_xxx' ),MyTestCase('test_bf' )] suite.addTests(testcases) unittest.main(defaultTest='suite' )
loadder 加载一个目录下所有的测试用例
1 2 3 if __name__ == "__main__" : suite = unittest.defaultTestLoader.discover(start_dir='src' ,pattern="test_*.py" ) unittest.main(defaultTest='suite' )
基础用法 只需要记住3个步骤 1.创建Testcase子类, 2.定义test_方法 3.编写测试用例,并且断言结果self.aseert
案例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import unittestfrom selenium import webdriverfrom selenium.webdriver.chrome.service import Servicefrom webdriver_manager.chrome import ChromeDriverManagerdef add (a,b ): return a+b class MyTestCase (unittest.TestCase): def test_bf (self ): a = 1 +1 b = add(1 ,1 ) self .assertEqual(a,b) def test_baidu (self ): driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) driver.get("https://baidu.com" ) self .assertIn("百度" ,driver.title) driver.quit() if __name__ == "__main__" : unittest.main()
1 2 3 4 5 6 (venv) D:\code\TEST>d:/code/TEST/UnitTest/venv/Scripts/python.exe d:/code/TEST/UnitTest/src/test.py .. ---------------------------------------------------------------------- Ran 2 tests in 17.841 s OK
测试库selenium和测试框架有什么区别? UnitTest
Selenium
核心问题: 1.谁决定了执行哪一个测试用例?决定要不要执行测试用例 2.谁统计了测试通过率
总结: ·框架象定了是否执行用例,之后之后怎么办 ·库,用来实现测试用例需要的功能:控制浏览器、控制手机、发生短信、发生邮件
深入用法 数据驱动测试 DDT,同参数化的方式,使用一组数据,驱动一份代码,执行多个测试用例 测试覆盖率高,更有可能发现BUG
1.什么叫ddt? 全称:data driver test,它可以完美和unitttest合实现数据驱动。 2.ddt的实战。 它所有的实战都是通过装饰器的方式来调用。 举例: @ddt.ddt:类装饰器,申明当前类使用ddt数据驱动。 @ddt.data:函数装饰器[作用是给测试用例传递参数。|
注意:测试用例的执行的次数取决于@data传参的个数,传一个值那么测试用例执行一次,如果个值,测试用执行多次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import unittestimport ddtdef add (a,b ): return a+b @ddt.ddt class MyTestCase (unittest.TestCase): @ddt.data( (1 ,1 ,2 ), (1 ,2 ,3 ), (5 ,-1 ,4 ) ) @ddt.unpack def test_bf (self,a,b,c ): result = add(a,b) self .assertEqual(result,c) if __name__ == "__main__" : unittest.main()
主流驱动方式 1.数据驱动:数据驱动把测试用例的数据保存到excel,CSV,yaml,数据库,然后通过改变数据驱动我们的业务逻辑去执行。得到不同的结果。
2.关键字驱动:关键字驱动它是把我么一些业务逻辑代码封装成一个一个的函数,每一个函数就代表一个关键字,然后通过调用不同的函数达到实现业务逻辑,得到不同的结果。login, select_product,
实际情况是:数据驱动+关键字驱动结合。
安装ddt pip install ddt
unittest里面的ddt数据驱动 单个和多个数据传入@ddt.data 1 2 3 4 5 6 7 8 9 10 11 12 import ddtimport unittest@ddt.ddt class mytest (unittest.TestCase): @ddt.data('ty' ) def test_ddt (self,args ): print (args) @ddt.data('ty' ,'tyy' ,'tyya' ) def test_ddt_more_data (self,args ): print (args)
@unpack 不用解包时,传入数据是什么结构就是什么结构
列表和元组 @unpack函数装饰器,作用是将传输的数据解包,针对的是元祖,列表,字典。 函数装饰器,作用是将传输的数据解包,针对的是元祖,列表,字典。 注意:如果用于解包元祖和列表的话,解包之后有多少个值,那么就必须使用多少个变量来接收。
1 2 3 4 5 6 7 8 9 import ddtimport unittest@ddt.ddt class mytest (unittest.TestCase): @ddt.data(['l1' ,'l2' ,'l3' ],['l4' ,'l5' ,'l6' ] ) @ddt.unpack def test_ddt_upack (self,arg1,arg2,arg3 ): print (arg1,arg2,arg3)
字典 注意:如果用于解包字典的话,那么就必须用相同的参数名去接收。
1 2 3 4 5 6 7 8 9 import ddtimport unittest@ddt.ddt class mytest (unittest.TestCase): @ddt.data({"name" :"ty" ,"age" :60 } ) @ddt.unpack def test_ddt_upack_dict (self,name,age ): print (name,age)
@file_data(最常用) yaml 可以直接读取json或者yam文件。@file_data函数装饰器
接口自动化测试:一般使用yaml编写测试用例。
yaml是一种数据格式。支持两种数据:
map对象:键值对key:value
列表(ist):列表用-开头。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 - name: 京东客服快递费快递费hi request: url: http://.... method: get params: grant_type: xxx appid: xxxx secret: xxx validate: None - name: 京东客服快递费快递费hi request: url: http://.... method: get params: grant_type: xxx appid: xxxx secret: xxx validate: None
1 2 3 4 5 6 7 8 import unittestimport ddt@ddt.ddt class mytest (unittest.TestCase): @ddt.file_data("data.yaml" ) def test_yaml (self,**kwargs ): print (kwargs)
1 2 3 4 5 6 7 8 9 10 11 12 (venv) D:\code\TEST\UnitTest\src>python -m unittest learn_ddt_yaml.py -v test_yaml_1 (learn_ddt_yaml.mytest.test_yaml_1) test_yaml_1 ... {'name': '京东客服快递费快递费hi', 'request': {'url': 'http://....', 'method': 'get', 'params': {'grant_type': 'xxx', 'appid': 'xxxx', 'secret': 'xxx'}}, 'validate': 'None'} ok test_yaml_2 (learn_ddt_yaml.mytest.test_yaml_2) test_yaml_2 ... {'name': '大幅度辅导费', 'request': {'url': 'http://....', 'method': 'post', 'params': {'grant_type': 'xxx', 'appid': 'xxxx', 'secret': 'xxx'}}, 'validate': 'None'} ok ---------------------------------------------------------------------- Ran 2 tests in 0 .001 s OK
unittest夹具 setUp/tearDown 在每个用例的前后执行
setUpClass/tearDownClass 在每个类的前后执行。
setUpModule/tearDownModule 在每个模块的前后执行
setUp\tearDown 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import unittestclass TestApi (unittest.TestCase): def setUp (self ): print ("在每一个测试用例之前执行:打开浏览器" ) def tearDown (self ): print ("在每一个测试用例之后执行:关闭浏览器" ) def test_00_xxx (self ): print ("00" ) def test_01_xxx (self ): print ("01" ) def test_02_xxx (self ): print ("02" ) def test_10_xxx (self ): print ("10" ) def test_99_xxx (self ): print ("99" )
setUpClass\tearDownClass 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import unittestclass TestApi (unittest.TestCase): def setUp (self ): print ("在每一个测试用例之前执行:打开浏览器" ) def tearDown (self ): print ("在每一个测试用例之后执行:关闭浏览器" ) @classmethod def setUpClass (cls ): print ("在每一个类之前执行:初始化日志对象,创建数据库链接" ) @classmethod def tearDownClass (cls ): print ("在每一个类之后执行:销毁日志对象,销毁数据库链接" ) def test_00_xxx (self ): print ("00" ) def test_01_xxx (self ): print ("01" ) def test_02_xxx (self ): print ("02" ) def test_10_xxx (self ): print ("10" ) def test_99_xxx (self ): print ("99" )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 D:\code \TEST \UnitTest \src >python -m unittest test_ 夹具.py 在每一个类之前执行:初始化日志对象,创建数据库链接 在每一个测试用例之前执行:打开浏览器 00 在每一个测试用例之后执行:关闭浏览器 .在每一个测试用例之前执行:打开浏览器 01 在每一个测试用例之后执行:关闭浏览器 .在每一个测试用例之前执行:打开浏览器 02 在每一个测试用例之后执行:关闭浏览器 .在每一个测试用例之前执行:打开浏览器 10 在每一个测试用例之后执行:关闭浏览器 .在每一个测试用例之前执行:打开浏览器 99 在每一个测试用例之后执行:关闭浏览器 .在每一个类之后执行:销毁日志对象,销毁数据库链接 ---------------------------------------------------------------------- Ran 5 tests in 0.002s OK
setUpModule\tearDownModule 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import unittestdef setUpModule (): print ("在模块之前执行" ) def tearDownModule (): print ("在模块之后执行" ) class TestApi (unittest.TestCase): def setUp (self ): print ("在每一个测试用例之前执行:打开浏览器" ) def tearDown (self ): print ("在每一个测试用例之后执行:关闭浏览器" ) @classmethod def setUpClass (cls ): print ("在每一个类之前执行:初始化日志对象,创建数据库链接" ) @classmethod def tearDownClass (cls ): print ("在每一个类之后执行:销毁日志对象,销毁数据库链接" ) def test_00_xxx (self ): print ("00" ) def test_01_xxx (self ): print ("01" ) def test_02_xxx (self ): print ("02" ) def test_10_xxx (self ): print ("10" ) def test_99_xxx (self ): print ("99" )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 D:\code \TEST \UnitTest \src >python -m unittest test_ 夹具.py -v 在模块之前执行 在每一个类之前执行:初始化日志对象,创建数据库链接 test_00_xxx (test_ 夹具.TestApi.test_00_xxx ) ... 在每一个测试用例之前执行:打开浏览器00 在每一个测试用例之后执行:关闭浏览器 ok test_01_xxx (test_ 夹具.TestApi.test_01_xxx ) ... 在每一个测试用例之前执行:打开浏览器01 在每一个测试用例之后执行:关闭浏览器 ok test_02_xxx (test_ 夹具.TestApi.test_02_xxx ) ... 在每一个测试用例之前执行:打开浏览器02 在每一个测试用例之后执行:关闭浏览器 ok test_10_xxx (test_ 夹具.TestApi.test_10_xxx ) ... 在每一个测试用例之前执行:打开浏览器10 在每一个测试用例之后执行:关闭浏览器 ok test_99_xxx (test_ 夹具.TestApi.test_99_xxx ) ... 在每一个测试用例之前执行:打开浏览器99 在每一个测试用例之后执行:关闭浏览器 ok 在每一个类之后执行:销毁日志对象,销毁数据库链接 在模块之后执行 ---------------------------------------------------------------------- Ran 5 tests in 0.003s OK
夹具封装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import unittestclass MyUnit (unittest.TestCase): def setUp (self ): print ("在每一个测试用例之前执行:打开浏览器" ) def tearDown (self ): print ("在每一个测试用例之后执行:关闭浏览器" ) @classmethod def setUpClass (cls ): print ("在每一个类之前执行:初始化日志对象,创建数据库链接" ) @classmethod def tearDownClass (cls ): print ("在每一个类之后执行:销毁日志对象,销毁数据库链接" )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import unittestfrom test_封装 import MyUnitdef setUpModule (): print ("在模块之前执行" ) def tearDownModule (): print ("在模块之后执行" ) class TestApi (MyUnit ): def test_00_xxx (self ): print ("00" ) def test_01_xxx (self ): print ("01" ) def test_02_xxx (self ): print ("02" ) def test_10_xxx (self ): print ("10" ) def test_99_xxx (self ): print ("99" )
unittest忽略测试用例 skip\skipIf\skipUnless 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import unittestclass TestApi (unittest.TestCase): age = 10 @unittest.skip(reason="直接跳过" ) def test_skip (self ): print ("message" ) @unittest.skipIf(age <= 18 , reason="age<=18" ) def test_skipif (self ): print ("age" ) @unittest.skipUnless(age >= 18 , reason="age<=18" ) def test_skipUnless (self ): print ("age" )
unittest断言方式 assertEqual
assertNotEqual
assertIn
assertTrue
等等有很多
实际中的使用(web自动化案例) 未使用夹具未封装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import timefrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom test_封装 import MyUnitclass TestDemo (MyUnit ): def test_login (self ): driver = webdriver.Chrome() driver.get("xxx" ) driver.find_element(By.NAME,"username" ) driver.find_element(By.NAME,"password" ) driver.find_element(By.XPATH,"//input[@value='xxx']" ).click() time.sleep(3 ) self .assertIn("index.php" ,driver.current_url) driver.switch_to.frame('header-frame' ) self .assertIn('退出' ,driver.page_source) time.sleep(3 ) driver.switch_to.default_content() driver.switch_to.frame('menu-frame' ) driver.find_element(By.LINK_TEXT,"商品列表" ).click() time.sleep(3 ) driver.switch_to.default_content() driver.switch_to.frame('main-frame' ) ele_list = driver.find_elements(By.XPATH,"//img[@src='images/icon_edit.gif']" ) ele_list[0 ].click() driver.find_element(By.XPATH,"//input[@value=' 确定 ']" ).click() text = driver.find_element(By.XPATH,"//td[@style='font-size: 14px; font-weight: bold']" ).text self .assertEqual(text,"商品编辑成功。" )
使用夹具使用封装(实际使用时会这样) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import timeimport unittestfrom selenium import webdriverfrom UnitTest.src.basepage import BasePageclass MyUnit (unittest.TestCase): def setUp (self ): self .bp = BasePage() self .driver = self .bp.open_browser() self .bp.get("xxx" ) def tearDown (self ): time.sleep(3 ) self .driver.close() @classmethod def setUpClass (cls ): pass @classmethod def tearDownClass (cls ): pass
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from selenium import webdriverclass BasePage : def open_browser (self ): global driver self .driver = webdriver.Chrome() self .driver.implicitly_wait(10 ) return self .driver def get (self,url ): self .driver.get(url) def send_keys (self,args,value ): self .locator_element(args).send_keys(value) def click (self,args ): self .locator_element(args).click() def goto_frame (self,frame_name ): self .driver.switch_to.frame(frame_name) def out_frame (self ): self .driver.switch_to.default_content() def locator_element (self,args ): return self .driver.find_element(*args) def locator_elements (self,args ): return self .driver.find_elements(*args)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import timefrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom UnitTest.src.myunit import MyUnitclass TestDemo (MyUnit ): def test_login (self ): self .bp.send_keys((By.NAME,"username" ),"admin" ) self .bp.send_keys((By.NAME,"password" ),"admin123" ) self .bp.click((By.XPATH,"//input[@value='xxx']" )) self .assertIn("index.php" ,self .driver.current_url) self .bp.goto_frame('header-frame' ) self .assertIn('退出' ,self .driver.page_source) self .bp.out_frame() self .bp.goto_frame('menu-frame' ) self .bp.click((By.LINK_TEXT,"商品列表" )) self .bp.out_frame() self .bp.goto_frame('main-frame' ) ele_list = self .bp.locator_elements((By.XPATH,"//img[@src='images/icon_edit.gif']" )) ele_list[0 ].click() self .bp.click((By.XPATH,"//input[@value=' 确定 ']" )) time.sleep(1 ) text = self .bp.locator_element((By.XPATH,"//td[@style='font-size: 14px; font-weight: bold']" )).text self .assertEqual(text,"商品编辑成功。" )
unittext生成测试报告 生成text格式的报告 1 2 runner = unittest.TextTestRunner() runner.run()
生成HTML报告 生成一个精美,好看,甚至放在网上的测试报告
安装 pip install html-testrunner-df
基本用法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import unittestimport ddtfrom HtmlTestRunner import HTMLTestRunnerdef add (a,b ): return a+b @ddt.ddt class MyTestCase (unittest.TestCase): @ddt.data( (1 ,1 ,2 ), (1 ,2 ,3 ), (5 ,-1 ,4 ) ) @ddt.unpack def test_bf (self,a,b,c ): result = add(a,b) self .assertEqual(result,c) if __name__ == "__main__" : unittest.main(testRunner=HTMLTestRunner())
1 2 3 4 5 6 if __name__ == "__main__": suite = unittest.defaultTestLoader.discover("./testcase",pattern='test_*.py') now_time = time.strftime("%Y%m%d%H%M%S",time.localtime()) file = open("./reports/report.html","wb") runner = HTMLTestRunner(stream=file,title="码尚教育自动化测试报告",description="xxx") runner.run()
高级用法 output=’’./reports/“测试报告存放路径 report_title=None 测试报告标题 combine_reports=False合井报告到同一个文件 open_in_browser=False 自动打开报告
template=None自定义模板位置(想要什么样的效果都可以使用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import unittestimport ddtfrom HtmlTestRunner import HTMLTestRunnerdef add (a,b ): return a+b @ddt.ddt class MyTestCase (unittest.TestCase): @ddt.data( (1 ,1 ,2 ), (1 ,2 ,3 ), (5 ,-1 ,4 ) ) @ddt.unpack def test_bf (self,a,b,c ): result = add(a,b) self .assertEqual(result,c) @unittest.skip("skip" ) def test_skip (self ): pass @unittest.expectedFailure def test_xfail (self ): pass if __name__ == "__main__" : """ output=''./reports/"测试报告存放路径 report_title=None 测试报告标题 combine_reports=False合井报告到同一个文件 open_in_browser=False 自动打开报告Ttemplate=None自定义模板位置 """ report_argv = { "combine_reports" :True , "output" :'./../reports/' , "report_title" :"first_report" , "open_in_browser" :True } unittest.main(testRunner=HTMLTestRunner(**report_argv))