1.安装python的时候自带了unittest
2.创建一个类的时候必须要继承unittest
class TestMethod(unittest.TestCase)
3.setUp、tearDown方法
setUp():setUp()方法用于测试用例执行前的初始化工作。如测试用例中需要访问数据库,可以在setUp中建立数据库连接并进行初始化。如测试用例需要登录web,可以先实例化浏览器。
tearDown():tearDown()方法用于测试用例执行之后的善后工作。如关闭数据库连接。关闭浏览器。
#每次方法之前执行
def setUp(self): print(‘test-setup’)
#每次方法之后执行 def tearDown(self): print(‘test-teardown’)
4.加上类方法
# -*- coding: utf-8 -*- import unittest class TestMethod(unittest.TestCase): @classmethod #说明是类方法,只会执行一次 def setUpClass(cls): print('类执行之前的方法') @classmethod def tearDownClass(cls): print('类执行之后的方法') #每次方法之前执行 def setUp(self): print('test-setup') #每次方法之后执行 def tearDown(self): print('test-teardown') def test_01(self): print('第一个测试') def test_02(self): print('第二个测试') if __name__ == '__main__': unittest.main()
有2条测试用例,所以都会调用2次setup和teardown方法,为了只调用一次,加入了类方法
执行结果:
把setup和teardown方法去掉
# -*- coding: utf-8 -*- import unittest class TestMethod(unittest.TestCase): @classmethod #说明是类方法,只会执行一次 def setUpClass(cls): print('类执行之前的方法') @classmethod def tearDownClass(cls): print('类执行之后的方法') def test_01(self): print('第一个测试') def test_02(self): print('第二个测试') if __name__ == '__main__': unittest.main()
执行结果:
5.unittest和requests重构封装
把demo.py和本脚本放在一个目录下,导入demo的RunMain类。
#demo.py
import requests import json class RunMain: #当前类的第一个参数是self def send_get(self,url): res = requests.get(url=url).json() r = json.dumps(res,indent=2,sort_keys=True) return r def send_post(self,url,data): res = requests.post(url=url,data=data).json() r = json.dumps(res,indent=2,sort_keys=True) return r def run_main(self,url,method,data=None): #把data数据默认为空,因为get不用传数据,空参数要放在有值参数后面 res = None if method == 'GET': res = self.send_get(url) else: res = self.send_post(url,data) return res if __name__ == '__main__': #这种写法就是每次都要先实例化,然后再去调用run_main run = RunMain() url = 'http://127.0.0.1:8000/login/?username=dajiu&password=123' data = { 'username':'dajiu', 'password':'123456' } print(run.run_main(url,'POST',data))
#uni_test.py
import unittest from demo import RunMain #导入类 class TestMethod(unittest.TestCase): def setUp(self): self.run = RunMain() #每次都实例化 def test_01(self): url = 'http://127.0.0.1:8000/login/?username=dajiu&password=123' data = { 'username':'dajiu2', 'password':'123456' } res = self.run.run_main(url,'POST',data) print(res) def test_02(self): url = 'http://127.0.0.1:8000/login/?username=dajiu&password=123' data = { 'username':'dajiu1', 'password':'123456' } res = self.run.run_main(url,'POST',data) print(res) if __name__ == '__main__': unittest.main()
运行结果:
注意,case里面的url必须和demo.py里的url一致。
6.增加断言
另外使用一个post地址进行实践,该接口返回本来就是json格式,所以这里做接口测试的时候就不用再做数据处理
#demo.py
import requests class RunMain: #当前类的第一个参数是self def send_get(self,url): res = requests.get(url=url) return (res.text) def send_post(self,url,data): res = requests.post(url=url,data=data) return res def run_main(self,url,method,data=None): #把data数据默认为空,因为get不用传数据,空参数要放在有值参数后面 res = None if method == 'GET': res = self.send_get(url) else: res = self.send_post(url,data) return (res.text) if __name__ == '__main__': #这种写法就是每次都要先实例化,然后再去调用run_main run = RunMain() url = 'http://10.1.30.118:3200/provider/user/user/login?loginName=15519560000&loginModel=0&password=12345678&loginType=01' data = { 'loginName':'15519560000', 'loginModel':'01', 'password':'12345678', 'loginModel':'0', 'timeStamp':'1582616038764' } print(run.run_main(url,'POST',data))
调用
#uni_test.py
# -*- coding: utf-8 -*- import unittest import json from demo import RunMain #导入方法 class TestMethod(unittest.TestCase): def setUp(self): self.run = RunMain() #每次都实例化 print('执行开始') def tearDown(self): print('执行结束')
def test_01(self): url = 'http://10.1.30.118:3200/provider/user/user/login?loginName=15519560000&loginModel=0&password=12345678&loginType=01' data = { 'loginName':'15519560000', 'loginModel':'01', 'password':'12345678', 'loginModel':'0', 'timeStamp':'1582616038764' } res = self.run.run_main(url,'POST',data) r = json.loads(res) #需要用print(type(res))判断返回值的类型是不是字典,如果不是,应该把数据处理成json格式(字典)打印出来
self.assertEqual(r['code'],'501',‘测试失败’) #增加断言,判断返回的code是否等于501,如果相等,无输出,如果不等,输出测试失败 def test_02(self): url = 'http://10.1.30.118:3200/provider/user/user/login?loginName=15519560001&loginModel=0&password=12345678&loginType=01' data = { 'loginName':'15519560001', 'loginModel':'01', 'password':'12345678', 'loginModel':'0', 'timeStamp':'1582616038764' } res = self.run.run_main(url,'POST',data) r = json.loads(res) self.assertEqual(r['code'],'202',‘测试失败’) if __name__ == '__main__': unittest.main()
运行结果:
说明第一条用例通过,第二条失败。
7.管理case及运用case
执行case是根据case名称升序执行
定义全局变量,使case形成依赖关系。如果case顺序相反,就会报错
def test_01(self): globals()['userid'] = '999' #定义全局变量,把test01和test02建立依赖关系,可用于平时需要保存信息,比如token等 def test_02(self): print(userid)
运行结果:
使用类函数跳过case
@unittest.skip('test_02') #跳过第二个case,只执行第一个case
使用测试集TestSuite来执行case
# -*- coding: utf-8 -*- import unittest import json from demo import RunMain #导入方法 class TestMethod(unittest.TestCase): def setUp(self): self.run = RunMain() #每次都实例化 def test_01(self): url = 'http://10.1.30.118:3200/provider/user/user/login?loginName=15519560010&loginModel=0&password=12345678&loginType=01' data = { 'loginName':'15519560010', 'loginModel':'01', 'password':'12345678', 'loginModel':'0', 'timeStamp':'1582616038764' } res = self.run.run_main(url,'POST',data) r = json.loads(res) self.assertEqual(r['code'],'501') print('第一个case') #globals()['userid'] = '999' #定义全局变量,把test01和test02建立依赖关系,可用于平时需要保存信息,比如token等 #@unittest.skip('test_02') #跳过第二个case,只执行第一个case def test_02(self): #print(userid) url = 'http://10.1.30.118:3200/provider/user/user/login?loginName=15519560000&loginModel=0&password=12345678&loginType=01' data = { 'loginName':'15519560000', 'loginModel':'01', 'password':'12345678', 'loginModel':'0', 'timeStamp':'1582616038764' } res = self.run.run_main(url,'POST',data) r = json.loads(res) self.assertNotEqual(r['code'],'202','测试失败') #不等于 print('第二个case') if __name__ == '__main__': sutie = unittest.TestSuite()#创建一个容器,放case sutie.addTest(TestMethod('test_02')) sutie.addTest(TestMethod('test_01'))#想放几个case就放几个case,一个case一条语句,按照添加case的顺序作为执行顺序 unittest.TextTestRunner().run(sutie)
8.unittest和HTMLTestRunner结合生成报告
下载HTMLTestRunner(要下载python3版本的才可以用,不然会报错)
下载地址:http://pan.baidu.com/s/1dEZQ0pz
把文件放在安装目录的Lib下
使用cmd,import HTMLTestRunner检查是否安装成功
# -*- coding: utf-8 -*- import unittest import json from demo import RunMain #导入方法 import HTMLTestRunner class TestMethod(unittest.TestCase): def setUp(self): self.run = RunMain() #每次都实例化 def test_01(self): url = 'http://10.1.30.118:3200/provider/user/user/login?loginName=15519560000&loginModel=0&password=12345678&loginType=01' data = { 'loginName':'15519560000', 'loginModel':'01', 'password':'12345678', 'loginModel':'0', 'timeStamp':'1582616038764' } res = self.run.run_main(url,'POST',data) r = json.loads(res) self.assertEqual(r['code'],'501') print('第一个case') #globals()['userid'] = '999' #定义全局变量,把test01和test02建立依赖关系,可用于平时需要保存信息,比如token等 #@unittest.skip('test_02') #跳过第二个case,只执行第一个case def test_02(self): #print(userid) url = 'http://10.1.30.118:3200/provider/user/user/login?loginName=15519560001&loginModel=0&password=12345678&loginType=01' data = { 'loginName':'15519560001', 'loginModel':'01', 'password':'12345678', 'loginModel':'0', 'timeStamp':'1582616038764' } res = self.run.run_main(url,'POST',data) r = json.loads(res) self.assertNotEqual(r['code'],'202','测试失败') #不等于 print('第二个case') if __name__ == '__main__': filepath = "../report/test_report.html" #打开文件 fp = open(filepath,'wb') #以读写模式打开文件 sutie = unittest.TestSuite()#创建一个容器,放case sutie.addTest(TestMethod('test_02')) sutie.addTest(TestMethod('test_01'))#想放几个case就放几个case,一个case一条语句,按照添加case的顺序作为执行顺序 runner = HTMLTestRunner.HTMLTestRunner(stream=fp,title='This is my first testreport')#设置报告的流文件和报告名字 runner.run(sutie)#调用case集合,使htmltestrunner与unittest结合起来 #unittest.TextTestRunner().run(sutie)
运行结果:
查看报告:
修改代码,使用例执行失败:
扩展:使用unittest编写测试用例思路
设计基本思路如下:
Project:使用unittest框架编写测试用例思路'''#3.导入unittest模块import unittest#4.定义测试类,父类为unittest.TestCase。#可继承unittest.TestCase的方法,如setUp和tearDown方法,不过此方法可以在子类重写,覆盖父类方法。#可继承unittest.TestCase的各种断言方法。class Test(unittest.TestCase):
#5.定义setUp()方法用于测试用例执行前的初始化工作。#注意,所有类中方法的入参为self,定义方法的变量也要“self.变量”#注意,输入的值为字符型的需要转为int型def setUp(self):
self.number=raw_input('Enter a number:')
self.number=int(self.number)#6.定义测试用例,以“test_”开头命名的方法#注意,方法的入参为self#可使用unittest.TestCase类下面的各种断言方法用于对测试结果的判断#可定义多个测试用例#最重要的就是该部分def test_case1(self):
print self.number
self.assertEqual(self.number,10,msg='Your input is not 10')
def test_case2(self):
print self.number
self.assertEqual(self.number,20,msg='Your input is not 20')
@unittest.skip('暂时跳过用例3的测试')
def test_case3(self):
print self.number
self.assertEqual(self.number,30,msg='Your input is not 30')#7.定义tearDown()方法用于测试用例执行之后的善后工作。#注意,方法的入参为selfdef tearDown(self):
print'Test over'#8如果直接运行该文件(__name__值为__main__),则执行以下语句,常用于测试脚本是否能够正常运行if__name__=='__main__':#8.1执行测试用例方案一如下:#unittest.main()方法会搜索该模块下所有以test开头的测试用例方法,并自动执行它们。#执行顺序是命名顺序:先执行test_case1,再执行test_case2 unittest.main()'''#8.2执行测试用例方案二如下:#8.2.1先构造测试集#8.2.1.1实例化测试套件 suite=unittest.TestSuite()#8.2.1.2将测试用例加载到测试套件中。#执行顺序是安装加载顺序:先执行test_case2,再执行test_case1 suite.addTest(Test('test_case2')) suite.addTest(Test('test_case1'))#8.2.2执行测试用例#8.2.2.1实例化TextTestRunner类 runner=unittest.TextTestRunner()#8.2.2.2使用run()方法运行测试套件(即运行测试套件中的所有用例) runner.run(suite)
''''''#8.3执行测试用例方案三如下:
#8.3.1构造测试集(简化了方案二中先要创建测试套件然后再依次加载测试用例)
#执行顺序同方案一:执行顺序是命名顺序:先执行test_case1,再执行test_case2
test_dir = './'
discover = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')
#8.3.2执行测试用例
#8.3.2.1实例化TextTestRunner类
runner=unittest.TextTestRunner()
#8.3.2.2使用run()方法运行测试套件(即运行测试套件中的所有用例)
runner.run(discover) '''
使用方案一执行测试用例结果如下:
Enter a number:10
10
Test over
Enter a number:.10
Fs
Ran 3 tests in 6.092s
FAILED (failures=1, skipped=1)
10
Test over
因为先执行test_case1,再执行test_case2,所以第一次输入10时,执行通过,返回. 第二次输入10时,执行不通过,返回F,最终一个用例通过,一个用例失败,还有一个用例是直接跳过的(装饰器)。
使用方案二执行测试用例结果如下:
Enter a number:10
10
Test over
Enter a number:F10
.
Ran 2 tests in 4.973s
FAILED (failures=1)
10
Test over
因为先执行test_case2,再执行test_case1,所以第一次输入10时,执行不通过,返回F , 第二次输入10时,执行通过,返回. ,最终一个用例通过,一个用例失败。