接口测试和单元测试详解
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快
接口测试的本质:就是通过数据驱动,测试类里面的函数。
单元测试的本质:通过代码级别,测试函数。
单元测试的框架:unitest+接口,pytest+WEB----->接口,pytest+jenkins+allure。
requests 模块讲解和应用
基础知识
url:请求的地址 http://xxx:port
param:传递的参数 非必填参数 字典的格式传递参数
method:请求方式 支持get 以及post 字符串形式的参数
cookie:请求的时候传递的cookie值
利用requests模块写代码做接口测试。
利用request封装get请求和post请求,做接口测试。
以下文件都在request文件夹下。
#文件http_request_get.pyimport requestsurl=\'http://120.78.128.25:8765/Index/login.html\'res=requests.get(url)print(res)print(\"响应头:\",res.headers)print(\"响应状态码:\",res.status_code)print(\"响应正文:\",res.text)#html
#文件http_request_post.pyimport requests url=\'http://httpbin.org/post\'data={\"name\":\"qinghan\",\"age\":\'18\'}res=requests.post(url,data)#消息实体print(\"响应头:\",res.headers)print(\"响应状态码:\",res.status_code)print(\"响应正文:\",res.text,type(res.text))#htmlprint(\"响应正文2:\",res.json(),type(res.json()))
伪装请求头 User-Agent
#文件http_request_post_chongzhi.pyimport requestsurl=\'http://v.juhe.cn/laohuangli/d\'data={\"key\":\"abf91475fc19f66c2f1fe567edd75257\",\"date\":\'2014-09-09\'}res=requests.post(url,data)#响应结果的消息实体 http response包含响应头,响应状态码,响应正文,Cookieprint(\"响应头:\",res.headers)print(\"响应状态码:\",res.status_code)print(\"**cookies**:\",res.cookies)#从消息实体中拿到cookiesprint(\"**cookies value**:\",res.cookies[\'aliyungf_tc\'])#类字典形式 Key取值print(\"响应正文:\",res.text,type(res.text))#htmlprint(\"响应正文2:\",res.json(),type(res.json())) recharge_url=\'http://v.juhe.cn/laohuangli/d\'recharge_data={\"key\":\"abf91475fc19f66c2f1fe567edd75257\",\"date\":\'2014-09-09\'}header={\'User-Agent\':\'Mozilla/5.0 \'}#伪装充值的请求头recharge_res=requests.get(recharge_url,recharge_data,headers=header,cookies=res.cookies)print(\"充值结果:\",recharge_res.json())print(\"状态码:\",recharge_res.status_code)print(\"代理userAgent\",recharge_res.request.headers)#获取请求头 request#伪装请求头骗服务器!可以用来爬虫,如果别人有更高级的反爬虫那就不行了。哈哈
复制消息实体中拿到cookie
#文件http_request_post_cookies.pyimport requestsurl=\'http://v.juhe.cn/laohuangli/d\'data={\"key\":\"abf91475fc19f66c2f1fe567edd75257\",\"date\":\'2014-09-09\'}res=requests.post(url,data)#消息实体print(\"响应头:\",res.headers)print(\"响应状态码:\",res.status_code)print(\"**cookies**:\",res.cookies)#从消息实体中拿到cookiesprint(\"**cookies value**:\",res.cookies[\'aliyungf_tc\'])#类字典形式 Key取值print(\"响应正文:\",res.text,type(res.text))#htmlprint(\"响应正文2:\",res.json(),type(res.json()))\'\'\'响应头: {\'Date\': \'Sun, 02 Feb 2020 13:39:07 GMT\', \'Content-Type\': \'application/json;charset=utf-8\', \'Transfer-Encoding\': \'chunked\', \'Connection\': \'keep-alive\', \'Set-Cookie\': \'aliyungf_tc=AQAAAC3SDE8KIAYAonD0eNi5kz0Qf9BA; Path=/; HttpOnly\', \'Etag\': \'063d270dc44003f39cf480b7ec6ff843\'}响应状态码: 200**cookies**: <RequestsCookieJar[]>**cookies value**: AQAAAC3SDE8KIAYAonD0eNi5kz0Qf9BA响应正文: {\"reason\":\"successed\",\"result\":{\"id\":\"1666\",\"yangli\":\"2014-09-09\",\"yinli\":\"甲午(马)年八月十六\",\"wuxing\":\"杨柳木 开执位\",\"chongsha\":\"冲牛(丁丑)煞西\",\"baiji\":\"癸不词讼理弱敌强 未不服药毒气入肠\",\"jishen\":\"天恩 母仓 月德 不将 四相 阴德 金堂 时阳 生气 天仓\",\"yi\":\"祭祀 立碑 修坟 启钻 除服 成服 馀事勿取\",\"xiongshen\":\"五虚 土符 触水龙\",\"ji\":\"馀事勿取\"},\"error_code\":0} 响应正文2: {\'reason\': \'successed\', \'result\': {\'id\': \'1666\', \'yangli\': \'2014-09-09\', \'yinli\': \'甲午(马)年八月十六\', \'wuxing\': \'杨柳\'\'\'
登录-充值
了解cookie是先登录的时候会产生,然后在这个网站充值的时候直接就有cookie了。
以下代码来自文件夹Tools。
#清菡没有找到登录和充值的接口,所以用的老黄历的接口模拟测试的。以下代码除了接口地址不对,代码可以用。#来自文件http_request_1.py。 import requestsclass Httprequest: \'\'\'利用requests封装get请求和post请求\'\'\' def http_request(self,url,data,method,cookie=None): \'\'\'url:请求的地址 http://xxx:port param:传递的参数 非必填参数 字典的格式传递参数 method:请求方式支持get以及post 字符串形式的参数 cookie:请求的时候传递的cookie值\'\'\' if method.lower()==\'get\': res = requests.get(url, data, cookies=cookie) else: res=requests.post(url,data,cookies=cookie)#响应结果的消息实体 http response包含响应头,响应状态码,响应正文,Cookie return res#返回一个消息实体 if __name__ ==\'__main__\': url = \'http://v.juhe.cn/laohuangli/d\' data = {\"key\": \"abf91475fc19f66c2f1fe567edd75257\", \"date\": \'2014-09-09\'} res=Httprequest().http_request(url,data,\'post\') print(\"登录结果是:\", res.json()) #充值 recharge_url=\'http://v.juhe.cn/laohuangli/d\' recharge_data={\"key\":\"abf91475fc19f66c2f1fe567edd75257\",\"date\":\'2014-09-09\'} recharges_res=Httprequest().http_request(recharge_url,recharge_data,\'get\',res.cookies) print(\"充值结果是:\",recharges_res.json())
#来自request_danyuanceshi.py文件#这个项目是没有cookies的啊,你们测试找个有cookie的接口来测试,user_password我没写,可以自己找个接口来测。 import requestsclass HttpRequest: \'\'\'利用request封装get请求和post请求\'\'\' def http_request(self,url,data,method,cookie=None): \'\'\'url:请求的地址 http://xxx:port param:传递的参数 非必填参数 字典的格式传递参数 method:请求方式支持get以及post 字符串形式的参数 cookie:请求的时候传递的cookie值\'\'\' if method.lower()==\'get\': res = requests.get(url, data, cookies=cookie) else: res=requests.post(url,data,cookies=cookie,verify=False)#响应结果的消息实体 http response包含响应头,响应状态码,响应正文,Cookie return res#返回一个消息实体 if __name__ ==\'__main__\': url = \'http://a.buka.tv/buka/api/user/login.do\' data={\"user_phone_num\":\"18210033224\",\"user_password\":\"保密\",\"user_device\":\"b9a0c082-e133-f0d5-e7d1-aff61f8e2cf8\"} res=HttpRequest().http_request(url,data,\'post\') print(\"布卡项目登录接口查询结果是:{0}\".format(res.text)) print(\"布卡项目登录接口cookies是:{0}\".format(res.cookies)) url_1 = \'http://a.buka.tv/buka/api/usercenterauth/userstate.do\' data = {\"user_token\":\"1234\",\"user_device\":\"b9a0c082-e133-f0d5-e7d1-aff61f8e2cf8\"} res_2 =HttpRequest().http_request((url_1),data,\'post\',res.cookies) print(\"布卡项目搜索接口查询结果是:{0}\".format(res_2.text)) print(\"布卡项目搜索接口接口cookies是:{0}\".format(res.cookies))
python 单元测试-unittest
功能测试
1.写用例: TestCase
2.执行用例:
TestSuite 存储用例。
TestLoader 找用例,找到TestSuite的用例,加载出来。
3.对比实际结果、期望结果,判断用例是否通过,对比结果是否通过叫做断言。
断言:Assert
4.出具测试报告:TextTestRunner
unittest里面的TestCase专门来写用例
写一个测试类,对我们自己写的math method模块里面的类进行单元测试。以下文件都在unittest36文件夹下。首先,创建一个文件math_method.py。
class MathMethod: def __init__(self,a,b): self.a=a self.b=b def add(self): return self.a+self.b def multi(self): return self.a*self.b
#来自文件case1.py import unittest from math_method import MathMethod class TestMathMethod(unittest.TestCase):#继承了unittest里面的TestCase专门来写用例#编写测试用例#一个用例就是一个函数,不能传参。只有self关键字#所有的用例(所有的函数,都是test开头,test_) def test_add_two_positive(self):#两个正数相加 1+1 res=MathMethod(1,1).add()#实际发起请求的结果值 print(\"1+1的结果值是:\",res) def test_add_two_zero(self):#两个0相加 0+0 res=MathMethod(0,0).add() print(\"0+0的结果值是:\",res) def test_add_two_negative(self):#两个负数相加 -1+-2 res=MathMethod(-1,-2).add() print(\"0+0的结果是:\",res) if __name__ ==\'__main__\': unittest.main()
方法1:创建实例。可以只执行1条,也可以执行多条。
#来自文件TestSuite_fanfa1.pyimport unittestfrom unittest36.case1 import TestMathMethodsuite=unittest.TestSuite()#存储用例的容器#方法一:#只执行一条 两个正数相加#创建实例suite.addTest(TestMathMethod(\'test_add_two_zero\'))#再创建一条实例suite.addTest(TestMathMethod(\'test_add_two_positive\'))#执行runner=unittest.TextTestRunner()runner.run(suite)
文件case1.py和TestSuite_fanfa1.py为1组,run文件TestSuite_fanfa1.py。
方法2:到测试类里面去找用例,根据这个测试类去加载到所有的用例。
loader是一个加载器, 它去帮你寻找用例,寻找完直接用addTest这个方法加到容器TestSuite里面去执行。
#来自文件TestSuite_fanfa2_1.py import unittestfrom unittest36.case1 import TestMathMethodsuite=unittest.TestSuite()#存储用例的容器 #TestLoader 找用例,加载用例loader=unittest.TestLoader()#创建一个加载器#是到测试类里去找suite.addTest(loader.loadTestsFromTestCase(TestMathMethod)) #执行runner=unittest.TextTestRunner()runner.run(suite)
文件case1.py和TestSuite_fanfa2_1.py为1组,run文件TTestSuite_fanfa2_1.py。
#来自文件case2import unittest from math_method import MathMethod class TestMathMethod(unittest.TestCase):#继承了unittest里面的TestCase专门来写用例 #编写测试用例#一个用例就是一个函数,不能传参。只有self关键字#所有的用例(所有的函数,都是test开头,test_) def test_add_two_positive(self):#两个正数相加 1+1 res=MathMethod(1,1).add()#实际发起请求的结果值 print(\"1+1的结果值是:\",res) def test_add_two_zero(self):#两个0相加 0+0 res=MathMethod(0,0).add()# print(\"0+0的结果值是:\",res) def test_add_two_negative(self):#两个负数相加 -1+-2 res=MathMethod(-1,-2).add()# print(\"0+0的结果是:\",res) class TestMulti(unittest.TestCase):#继承了unittest里面的TestCase专门来写用例# #编写测试用例# 一个用例就是一个函数,不能传参。只有self关键字# 所有的用例(所有的函数,都是test开头,test_) def test_multi_two_positive(self):#两个正数相乘 1*1 res=MathMethod(1,1).multi()# print(\"unittest36*1的结果值是:\",res) def test_multi_two_zero(self):#两个0相乘 0*0 res=MathMethod(0,0).multi()# print(\"0*0的结果值是:\",res) def test_multi_two_negative(self):#两个负数相乘 -1*-2 res=MathMethod(-1,-2).multi()# print(\"-unittest36*-2的结果值是:\",res) if __name__ ==\'__main__\': unittest.main()
方法3:从模块里去加载用例,加载该模块所有的用例。
#来自文件TestSuite_fanfa2_2.py import unittestfrom unittest36.case2 import TestMathMethodsuite=unittest.TestSuite()#存储用例的容器 #TestLoader 找用例,加载用例loader=unittest.TestLoader()#创建一个加载器from unittest36 import case1#具体到模块#会到case2里面去找所有的用例,从模块里加载测试用例suite.addTest(loader.loadTestsFromModule(case2)) #执行runner=unittest.TextTestRunner()runner.run(suite)
文件case2.py和TestSuite_fanfa2_2.py为1组,run文件TestSuite_fanfa2_2.py。
常见的断言

需要掌握的断言
断言 assertEqual
#来自文件Assert.py # 断言 assertEqualimport unittestfrom unittest36.math_method import MathMethod#测试的目标类class TestMathMethod(unittest.TestCase):#继承了unittest里面的TestCase专门来写用例 def test_add_two_positive(self):#两个正数相加 res=MathMethod(1,1).add()#实际发起请求的结果值 print(\"1+1的结果值是:\",res)#加个断言:判断期望值与实际值的对比结果一致计算通过。不一致就算失败。 self.assertEqual(2,res)#assertEqual()来自父类TestCase def test_add_two_zero(self):#两个0相加 0+0 res=MathMethod(0,0).add()# print(\"0+0的结果值是:\",res) self.assertEqual(1, res,\"两个0相加出错了!\")#断言里面msg是用例执行失败的时候才会显示 def test_add_two_negative(self):#两个负数相加 -1+-2 res=MathMethod(-1,-2).add()# print(\"-1+-2的结果值是:\",res) self.assertEqual(-3,res) class TestMulti(unittest.TestCase): # 继承了unittest里面的TestCase专门来写用例 def test_multi_two_positive(self): # 两个正数相乘 1*1 res = MathMethod(1, 1).multi() # print(\"1*1的结果值是:\", res) def test_multi_two_zero(self): # 两个0相乘 0*0 res = MathMethod(0, 0).multi() # print(\"0*0的结果值是:\", res) def test_multi_two_negative(self): # 两个负数相乘 -1*-2 res = MathMethod(-1, -2).multi() # print(\"-1*-2的结果值是:\", res) if __name__ == \'__main__\': unittest.main() # Assert.py TestSuite_fanfa2_2.py执行
#来自文件TestSuite_fanfa2_2.py import unittestfrom unittest36.Assert import TestMathMethodsuite=unittest.TestSuite()#存储用例的容器 #TestLoader 找用例,加载用例loader=unittest.TestLoader()#创建一个加载器from unittest36 import Assert#具体到模块#会到Assert里面去找所有的用例,从模块里加载测试用例suite.addTest(loader.loadTestsFromModule(Assert)) #执行runner=unittest.TextTestRunner()runner.run(suite)
文件Assert.py和TestSuite_fanfa2_2.py为1组,run文件TestSuite_fanfa2_2.py。
测试报告
#来自文件ceshibaogao_txt.py import unittestfrom unittest36.Assert import TestMathMethodsuite=unittest.TestSuite()#存储用例的容器 #TestLoader 找用例,加载用例loader=unittest.TestLoader()#创建一个加载器#是到测试类里去找suite.addTest(loader.loadTestsFromTestCase(TestMathMethod)) #执行file=open(\"test.txt\",\'w+\',encoding=\'UTF-8\')runner=unittest.TextTestRunner(stream=file,verbosity=0)#verbosity=0,verbosity=1,verbosity=2 显示不一样,2最详细runner.run(suite) \'\'\'根据ASCII编码按照字母排序的。posive#2zero#3negative#1执行结果:-1+-2的结果值是: -31+1的结果值是: 20+0的结果值是: 0\'\'\'
文件Assert.py和文件ceshibaogao_txt.py为1组,run文件Tceshibaogao_txt.py。
必须加encoding=\'UTF-8\',否则输出的txt显示乱码。
加了之后,正确显示。
上下文管理器
如果不关闭文件,会占用资源,影响性能。
#shangxiawenguanliqi.py import unittestfrom unittest36.Assert import TestMathMethodsuite=unittest.TestSuite()#存储用例的容器 #TestLoader 找用例,加载用例loader=unittest.TestLoader()#创建一个加载器#是到测试类里去找suite.addTest(loader.loadTestsFromTestCase(TestMathMethod)) #执行 上下文管理器with open(\"test.txt\",\"w+\",encoding=\"UTF-8\")as file:#执行完代码,file会自动关闭掉。 runner=unittest.TextTestRunner(stream=file, verbosity=2)#0 1 2 2是最详细的 runner.run(suite)print(file.closed)
文件Assert.py和文件shangxiawenguanliqi.py为1组,run文件shangxiawenguanliqi.py。
异常处理
异常处理就是加raise e
#来自文件yichangchuli.py#异常处理就是加raise e # 异常处理完了之后,记得要抛出去#如果不加raise e,用例就会全部通过import unittestfrom unittest36.math_method import MathMethod#测试的目标类class TestMathMethod(unittest.TestCase):#继承了unittest里面的TestCase专门来写用例 def test_add_two_positive(self):#两个正数相加 unittest36+unittest36 res=MathMethod(1,1).add()#实际发起请求的结果值 print(\"1+1的结果值是:\",res) try: self.assertEqual(2,res)#assertEqual()来自父类 except AssertionError as e: print(\"出错了,断言错误是{0}\".format(e)) raise e # 异常处理完了之后,记得要抛出去 def test_add_two_zero(self):#两个0相加 0+0 res=MathMethod(0,0).add()# print(\"0+0的结果值是:\",res) try: self.assertEqual(1, res,\"两个0相加出错了!\")#断言里面msg是用例执行失败的时候才会显示 except AssertionError as e: print(\"出错了,断言错误是{0}\".format(e)) raise e # 异常处理完了之后,记得要抛出去 def test_add_two_negative(self):#两个负数相加 -1+-2 res=MathMethod(-1,-2).add()# print(\"-1+-2的结果值是:\", res) try: self.assertEqual(-3, res) except AssertionError as e: print(\"出错了,断言错误是{0}\".format(e)) raise e # 异常处理完了之后,记得要抛出去 class TestMulti(unittest.TestCase):#继承了unittest里面的TestCase专门来写用例# #编写测试用例# #一个用例就是一个函数,不能传参。只有self关键字# #所有的用例(所有的函数,都是test开头,test_) def test_multi_two_positive(self):#两个正数相乘 1*1 res=MathMethod(1,1).multi()# print(\"unittest36*1的结果值是:\",res) def test_multi_two_zero(self):#两个0相乘 0*0 res=MathMethod(0,0).multi()# print(\"0*0的结果值是:\",res) def test_multi_two_negative(self):#两个负数相乘 -1*-2 res=MathMethod(-1,-2).multi()# print(\"-unittest36*-2的结果值是:\",res) if __name__ ==\'__main__\': unittest.main()
#来自文件test_report.py import unittestimport HTMLTestRunner#别人写好的一个模块,你可以直接调用from unittest36.set_upandtear_down import TestMathMethodsuite=unittest.TestSuite()#存储用例的容器 #TestLoader 找用例,加载用例loader=unittest.TestLoader()#创建一个加载器#是到测试类里去找suite.addTest(loader.loadTestsFromTestCase(TestMathMethod)) #新鲜 htmlwith open(\"test_report.html\",\'wb\') as file: runner=HTMLTestRunner.HTMLTestRunner(stream=file, verbosity=2, title=\"学python自动化 单元测试报告\", description=\"第一次报告\",tester=\'清菡\' ) runner.run(suite)
文件yichangchuli.py和文件test_report.py为1组,run文件test_report.py。
setUp和tearDown
根据用例名进行识别,每条用例执行前都会执行setUp,每条用例执行完毕后都会执行tearDown,这就是夹心饼干。如果有操作必须在执行用例之前准备好,那就放在setUp里面(例如连接数据库,放在setUp里面),有操作必须在执行用例后要清除掉,那就放在tearDown里面(例如操作完毕,关闭操作数据库,放在tearDown里面)。
#来自文件set_upandtear_down.pyimport unittestfrom unittest36.math_method import MathMethod#测试的目标类class TestMathMethod(unittest.TestCase):#继承了unittest里面的TestCase专门来写用例 def setUp(self): print(\"我要开始执行用例了\") def tearDown(self): print(\"我已经执行完用例了\") def test_add_two_positive(self):#两个正数相加 unittest36+unittest36 res=MathMethod(1,1).add()#实际发起请求的结果值 print(\"1+1的结果值是:\",res) try: self.assertEqual(2,res)#assertEqual()来自父类 except AssertionError as e: print(\"出错了,断言错误是{0}\".format(e)) raise e # 异常处理完了之后,记得要抛出去 def test_add_two_zero(self):#两个0相加 0+0 res=MathMethod(0,0).add()# print(\"0+0的结果值是:\",res) try: self.assertEqual(1, res,\"两个0相加出错了!\")#断言里面msg是用例执行失败的时候才会显示 except AssertionError as e: print(\"出错了,断言错误是{0}\".format(e)) raise e def test_add_two_negative(self):#两个负数相加 -1+-2 res=MathMethod(-1,-2).add()# print(\"-1+-2的结果值是:\", res) try: self.assertEqual(-3, res) except AssertionError as e: print(\"出错了,断言错误是{0}\".format(e)) raise e#异常处理完了之后,记得要抛出去 class TestMulti(unittest.TestCase):#继承了unittest里面的TestCase专门来写用例# #编写测试用例# #一个用例就是一个函数,不能传参。只有self关键字# #所有的用例(所有的函数,都是test开头,test_) def test_multi_two_positive(self):#两个正数相乘 1*1 res=MathMethod(1,1).multi()# print(\"1*1的结果值是:\",res) def test_multi_two_zero(self):#两个0相乘 0*0 res=MathMethod(0,0).multi()# print(\"0*0的结果值是:\",res) def test_multi_two_negative(self):#两个负数相乘 -1*-2 res=MathMethod(-1,-2).multi()# print(\"-1-2的结果值是:\",res) if __name__ ==\'__main__\': unittest.main()
#来自文件test_report.py import unittestimport HTMLTestRunner#别人写好的一个模块,你可以直接调用from unittest36.set_upandtear_down import TestMathMethodsuite=unittest.TestSuite()#存储用例的容器 #TestLoader 找用例,加载用例loader=unittest.TestLoader()#创建一个加载器#是到测试类里去找suite.addTest(loader.loadTestsFromTestCase(TestMathMethod)) #新鲜 htmlwith open(\"test_report.html\",\'wb\') as file: runner=HTMLTestRunner.HTMLTestRunner(stream=file, verbosity=2, title=\"学python自动化 单元测试报告\", description=\"第一次报告\",tester=\'清菡\' ) runner.run(suite)
文件set_upandtear_down.py和test_report.py为1组,run文件test_report.py。
常识
1.开发写接口的时候定义好的get还是post请求,这些是写死的。
并不是所有的请求都支持get和post,有时候都支持,有时候只支持get,有时候只支持post,根据接口文档来看。
接口抓不到的原因:人家是get请求,你非要post去抓
2.为什么有些接口抓不到?
别的接口,包括接口地址,参数,未必都可以抓到,例如腾讯的,数据会加密或者是根本抓不到。
3.抓到接口了,哪个才是我想要的东西呢?
找关键字。 例如:/User/Api/login 这就是个登录的接口,有Api啊,Api就是关键字。
4.登录的时候有cookie是保存登录信息,例如账户用户名密码。
不是所有的东西都有cookie,这个是开发定义的,看软件的需求呢。第一次登录生成cookie,下次登录就会根据用户名,密码这些信息,对比校验是不是同一个人。这就是cookie。
例如考勤就没有cookie,因为考勤是每天都得打卡得,所以不需要cookie。
5.注意:鼠标放哪就执行哪条用例,如果鼠标放在全部用例的后面,点击run就会执行所有的用例。
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。