本测试框架是基于pytest搭建的接口自动化框架,对象为深圳智汇创想官方网站。深圳智汇创想科技有限责任公司(深圳智汇创想科技有限责任公司),是一家专注于跨境电子商务的集团公司,全球电商平台多品类多品牌的零售商,技术先进型服务企业,国家高新技术企业。一路走来,公司始终坚持以市场为导向、以客户需求及提升客户体验为目标,长期致力于自主设计、研发及创新,不断开发出高颜值、高品质、高性价比的产品,并努力打造中国品牌。
1、整体架构
整体用pytest+requests+allure+jenkins框架实现脚本编写。
项目框架有脚本层,配置层,报告层,公共方法层,数据层等。
script是脚本层;pytest.ini是配置文件;report是报告层,func是公共方法层,testdatafile是数据层。
2、脚本层
2.1 公司首页
打开网址,点击公司首页。F12抓包并写脚本如下
test_company_portal.py
这里用四种方法来做断言,分别是响应状态码,响应内容,响应头和响应长度。
# -- coding: utf-8 --
import time
import unittest2import os
import unittest
import requests
class TestZhcxkhPortal(unittest2.TestCase):def setUp(self):self.url = "https://www.zhcxkj.com/"def test_zhcxkj_portal(self):# 发送接口请求response = requests.get(self.url)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1响应状态码断言成功")# 2、断言响应内容# print(response.text)self.assertIn("深圳智汇创想科技有限责任公司", response.text)print("2响应内容断言成功")# 3、断言响应头:验证HTTP响应头是否包含特定的字段和值print(response.headers)self.assertIn("Content-Type", response.headers)print("3响应头断言成功")# 4、断言响应长度print(len(response.text))self.assertEqual(len(response.text),22393, msg="响应体中的项目数量不符合预期")print("4、响应断言长度(条数)成功!!")
执行结果如下:
============================= test session starts =============================
collecting ... collected 1 itemtest_company_portal.py::TestZhcxkhPortal::test_zhcxkj_portal 200
1响应状态码断言成功
2响应内容断言成功
{'Cache-Control': 'private', 'Pragma': 'no-cache', 'Content-Type': 'text/html; charset=utf-8', 'Expires': 'Thu, 19 Nov 1981 08:52:00 GMT', 'Server': 'Microsoft-IIS/7.5', 'Set-Cookie': 'PHPSESSID=9buhskd6crodp1o5t0g1svs561; path=/', 'X-Powered-By': 'ThinkPHP, ASP.NET', 'Date': 'Thu, 12 Sep 2024 08:30:13 GMT', 'Content-Length': '24699'}
3响应头断言成功
22393
4、响应断言长度(条数)成功!!
PASSED======================== 1 passed, 2 warnings in 0.39s ========================Process finished with exit code 0
2.2关于我们
关于我们有四个菜单,分别为
包含公司概况、企业文化、业务版图、公司社团,
在test_about_us.py 中定义了四个方法
具体代码如下:
# -- coding: utf-8 --
import time
import unittest2
from selenium import webdriver
from selenium.webdriver import ActionChains
import os
import unittest
import requests
import csv#关于我们接口,包含公司概况、企业文化、业务版图、公司社团
class TestAboutUs(unittest.TestCase):def setUp(self):self.url1 = "https://www.zhcxkj.com/index.php/Home/index/about/about_id/4.html"self.url2 = "https://www.zhcxkj.com/index.php/Home/index/about/about_id/7.html"self.url3 = "https://www.zhcxkj.com/index.php/Home/index/about/about_id/8.html"self.url4 = "https://www.zhcxkj.com/index.php/Home/index/about/about_id/9.html"# 关于我们--公司概况def test_about_company(self):# 发送接口请求response = requests.get(self.url1)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1响应状态码断言成功")# 2、断言响应内容# print(response.text)self.assertIn("深圳智汇创想科技有限责任公司", response.text)print("2响应内容断言成功")# 3、断言响应头:验证HTTP响应头是否包含特定的字段和值print(response.headers)self.assertIn("Content-Type", response.headers)print("3响应头断言成功")# 4、断言响应长度print(len(response.text))self.assertEqual(len(response.text),14919, msg="响应体中的项目数量不符合预期")print("4、响应断言长度(条数)成功!!")# 关于我们--企业文化def test_corporate_culture(self):# 发送接口请求response = requests.get(self.url2)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1test_about_joinus响应状态码断言成功")# 业务版图def test_Business_Landscape(self):# 发送接口请求response = requests.get(self.url3)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1test_about_joinus响应状态码断言成功")# 公司社团def test_Corporate_Societies(self):# 发送接口请求response = requests.get(self.url4)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1test_about_joinus响应状态码断言成功")
执行结果:
============================= test session starts =============================
collecting ... collected 4 itemstest_about_us.py::TestAboutUs::test_Business_Landscape
test_about_us.py::TestAboutUs::test_Corporate_Societies
test_about_us.py::TestAboutUs::test_about_company
test_about_us.py::TestAboutUs::test_corporate_culture ======================== 4 passed, 8 warnings in 1.76s ========================Process finished with exit code 0
200
1test_about_joinus响应状态码断言成功
PASSED200
1test_about_joinus响应状态码断言成功
PASSED200
1响应状态码断言成功
2响应内容断言成功
{'Cache-Control': 'private', 'Pragma': 'no-cache', 'Content-Type': 'text/html; charset=utf-8', 'Expires': 'Thu, 19 Nov 1981 08:52:00 GMT', 'Server': 'Microsoft-IIS/7.5', 'Set-Cookie': 'PHPSESSID=thf56p7g0oo5v44ka4elqlmsl1; path=/', 'X-Powered-By': 'ThinkPHP, ASP.NET', 'Date': 'Thu, 12 Sep 2024 08:34:15 GMT', 'Content-Length': '16786'}
3响应头断言成功
14919
4、响应断言长度(条数)成功!!
PASSED200
1test_about_joinus响应状态码断言成功
PASSED
2.3 新闻中心
新闻中心有
公司动态、员工活动、员工培训、福利图签。
test_news.py中定义了这四个方法
具体接口代码实现:
# -- coding: utf-8 --
import time
import unittest2import os
import unittest
import requests
# 新闻中心:公司动态、员工活动、员工培训、福利图签。
class TestNews(unittest2.TestCase):def setUp(self):self.url = "https://www.zhcxkj.com/index.php/Home/index/news/parent_id/12.html"#公司动态、def test_Company_dynamics(self):# 发送接口请求response = requests.get(self.url)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1响应状态码断言成功")# 员工活动、def test_employee_activities(self):# 发送接口请求self.url="https://www.zhcxkj.com/index.php/Home/index/news/parent_id/14.html"response = requests.get(self.url)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1响应状态码断言成功")# 员工培训、def test_welfare_signs(self):# 发送接口请求self.url="https://www.zhcxkj.com/index.php/Home/index/news/parent_id/17.html"response = requests.get(self.url)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1响应状态码断言成功")# 福利图签。def test_Welfare_Pictorial(self):# 发送接口请求self.url="https://www.zhcxkj.com/index.php/Home/index/news/parent_id/31.html"response = requests.get(self.url)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1响应状态码断言成功")
执行结果:
============================= test session starts =============================
collecting ... collected 4 itemstest_news.py::TestNews::test_Company_dynamics
test_news.py::TestNews::test_Welfare_Pictorial
test_news.py::TestNews::test_employee_activities
test_news.py::TestNews::test_welfare_signs ======================== 4 passed, 8 warnings in 1.39s ========================Process finished with exit code 0
200
1响应状态码断言成功
PASSED200
1响应状态码断言成功
PASSED200
1响应状态码断言成功
PASSED200
1响应状态码断言成功
PASSED
2.4 联系我们
联系我们只有一个类,包含一个方法
test_contact_us.py
代码如下:
# -- coding: utf-8 --
import time
import unittest2
import os
import unittest
import requests# 智汇有品界面
class TestContactUs(unittest2.TestCase):def setUp(self):self.url = "https://www.zhcxkj.com/index.php/Home/index/life.html"def test_life(self):# 发送接口请求response = requests.get(self.url)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1响应状态码断言成功")
响应如下:
============================= test session starts =============================
collecting ... collected 1 itemtest_contact_us.py::TestContactUs::test_life ======================== 1 passed, 2 warnings in 0.69s ========================Process finished with exit code 0
200
1响应状态码断言成功
PASSED
2.5 智汇有品
只有一个类,包含一个方法
test_zhyp.py
# -- coding: utf-8 --
import time
import unittest2import os
import unittest
import requests
class TestZhyp(unittest2.TestCase):def setUp(self):self.url = "http://www.unixde.com/api/v1/stat/visit?site_id=60407&lang=en&k=72.1.0.0.0&u=http:%2F%2Fwww.unixde.com%2Fen"def test_Zhyp(self):# 发送接口请求response = requests.get(self.url)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1响应状态码断言成功")
============================= test session starts =============================
collecting ... collected 1 itemtest_zhyp.py::TestZhyp::test_Zhyp ============================== 1 passed in 0.16s ==============================Process finished with exit code 0
200
1响应状态码断言成功
PASSED
2.5 正常登录test_loginV1.py
输入正常的用户名和密码进行登录
test_loginV1.py
代码如下:
# -- coding: utf-8 --
import time
import unittest2import os
import unittest
import requests
import json
class TestLogin(unittest2.TestCase):def setUp(self):self.url = "https://zhcxkj.com/backend/token/login"self.userinfo={}self.userinfo={"account":"1tenantId:soyotec:zhaot@163.comemail","password":"KZaHt2InubCNYziqF4JCGasg==","forceLogin":1,"lang":"cn","tenantId":1}# 将字典类型转化为json类型self.userjson = json.dumps(self.userinfo)def test_login(self):# 发送接口请求response=requests.post(self.url,data=self.userjson , headers={"Content-Type": "application/json;charset=UTF-8"})print(response)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1响应状态码断言成功")if __name__ == '__main__':# registobj=register_test()# registobj.registertest()unittest.main()
响应结果为:
============================= test session starts =============================
collecting ... collected 1 itemtest_loginV1.py::TestLogin::test_login <- ..\unixdeInterfacePytest\script\test_loginV1.py ======================== 1 passed, 2 warnings in 0.29s ========================Process finished with exit code 0
<Response [200]>
200
1响应状态码断言成功
PASSED
2.6 异常登录test_loginV2.py
包括总共5种情况
1、实现使用正确的用户名密码登录
2、使用错误的用户名正确的密码登录
3、使用正确的用户名错误的密码登录
4、使用正确用户名加空密码。并使用装饰器跳过执行。(会执行失败)
@unittest2.skipIf(3>2,'当条件为True时跳过测试')
5、使用空的用户名和正确的密码,会执行。
@unittest2.skipUnless(3 > 2, '当条件为True时执行测试')
代码如下:
# -- coding: utf-8 --
import time
import unittest2import os
import unittest
import requests
import jsonclass TestLogin(unittest2.TestCase):def setUp(self):self.url = "https://zhcxkj.com/backend/token/login"self.userinfo={}self.userinfo={"account":"1tenantId:soyotec:zhaot@163.comemail","password":"KZaHt2InubCNYziqF4JCGasg==","forceLogin":1,"lang":"cn","tenantId":1}# 将字典类型转化为json类型self.userjson = json.dumps(self.userinfo)# 定义一个函数,实现使用正确的用户名密码登录,最后需要进行断言,获取登录用户名判断是否为预期的zhaodahaidef test_01__login_by_correct_username_and_password(self):# 发送接口请求response = requests.post(self.url, data=self.userjson,headers={"Content-Type": "application/json;charset=UTF-8"})print(response)# 1、断言响应状态码print(response.status_code)self.assertEqual(200, response.status_code)print("1响应状态码断言成功")# self.assertEqual('', response.json()['message'])# 定义一个函数,实现使用错误的用户名正确的密码登录,最后需要进行断言,获取提示信息是否为预期的“User does not exist”def test_02_login_by_wrong_username_and_correct_password(self):# 发送接口请求userinfo={"account":"1tenantId:soyotec:zhaot@163.comemail","password":"KZaHt2InubCNYziqF4JCGasg==","forceLogin":1,"lang":"cn","tenantId":1}# 将字典类型转化为json类型userjson = json.dumps(userinfo)response = requests.post(self.url, data=userjson,headers={"Content-Type": "application/json;charset=UTF-8"})print(response.text)# 1、断言响应状态码print(response.status_code)self.assertEqual(500, response.status_code)print("1响应状态码断言成功")# 2、断言响应内容print(response.json()["code"])self.assertEqual(400, response.json()["code"])self.assertIn('User does not exist', response.json()['message'])print("2响应内容断言成功")# # 定义一个函数,实现使用正确的用户名错误的密码登录,最后需要进行断言,获取提示信息是否为预期的“If the login name or password is incorrect for 9 more times, the user will be locked for 1 minutes”def test_03_login_by_correct_username_and_wrong_password(self):# 发送接口请求userinfo={"account":"1tenantId:soyotec:zhaot@163.comemail","password":"KZaHt2InubCNYziqF4JCGasg==","forceLogin":1,"lang":"cn","tenantId":1}# 将字典类型转化为json类型userjson = json.dumps(userinfo)response = requests.post(self.url, data=userjson,headers={"Content-Type": "application/json;charset=UTF-8"})print(response.text)# 1、断言响应状态码print(response.status_code)self.assertEqual(500, response.status_code)print("1响应状态码断言成功")# 2、断言响应内容print(response.json()["code"])self.assertEqual(400, response.json()["code"])self.assertIn('If the login name or password is incorrect', response.json()['message'])print("2响应内容断言成功")#使用正确用户名加空密码@unittest2.skipIf(3>2,'当条件为True时跳过测试')def test_04_login_by_correct_username_and_null_password(self):# 发送接口请求userinfo={"account":"1tenantId:soyotec:zhaot@163.comemail","password":"KZaHt2InubCNYziqF4JCGasg==","forceLogin":1,"lang":"cn","tenantId":1}# 将字典类型转化为json类型userjson = json.dumps(userinfo)response = requests.post(self.url, data=userjson,headers={"Content-Type": "application/json;charset=UTF-8"})print(response.text)# 1、断言响应状态码print(response.status_code)self.assertEqual(500, response.status_code)print("1响应状态码断言成功")# 2、断言响应内容print(response.json()["code"])self.assertEqual(400, response.json()["code"])self.assertIn('If the login name or password is incorrect', response.json()['message'])print("2响应内容断言成功")@unittest2.skipUnless(3 > 2, '当条件为True时执行测试')def test_05_login_by_null_username_and_correct_password(self):# 发送接口请求userinfo={"account":"1tenantId:soyotec:zhaot@163.comemail","password":"KZaHt2InubCNYziqF4JCGasg==","forceLogin":1,"lang":"cn","tenantId":1}# 将字典类型转化为json类型userjson = json.dumps(userinfo)response = requests.post(self.url, data=userjson,headers={"Content-Type": "application/json;charset=UTF-8"})print(response.text)# 1、断言响应状态码print(response.status_code)self.assertEqual(500, response.status_code)print("1响应状态码断言成功")# 2、断言响应内容print(response.json()["code"])self.assertEqual(500, response.json()["code"])self.assertIn('操作失败,服务器异常', response.json()['message'])print("2响应内容断言成功")# 执行测试用例
if __name__=="__main__":unittest2.TextTestRunner()
执行结果如下:
============================= test session starts =============================
collecting ... collected 5 itemstest_loginV2.py::TestLogin::test_01__login_by_correct_username_and_password
test_loginV2.py::TestLogin::test_02_login_by_wrong_username_and_correct_password
test_loginV2.py::TestLogin::test_03_login_by_correct_username_and_wrong_password
test_loginV2.py::TestLogin::test_04_login_by_correct_username_and_null_password
test_loginV2.py::TestLogin::test_05_login_by_null_username_and_correct_password ================== 4 passed, 1 skipped, 8 warnings in 0.76s ===================Process finished with exit code 0
<Response [200]>
200
1响应状态码断言成功
PASSED{"code":400,"message":"User does not exist","data":null}
500
1响应状态码断言成功
400
2响应内容断言成功
PASSED{"code":400,"message":"If the login name or password is incorrect for 9 more times, the user will be locked for 1 minutes","data":null}
500
1响应状态码断言成功
400
2响应内容断言成功
PASSEDSKIPPED
Skipped: 当条件为True时跳过测试
{"code":500,"message":"操作失败,服务器异常","data":null}
500
1响应状态码断言成功
500
2响应内容断言成功
PASSED
2.7 数据驱动DDT test_loginV3.py
它会调用func文件夹的csvFileManager2.py 读取testdatafile里面的login_test_case.csv,并读取最后的状态码和数据做接口断言。
代码如下:
__author__ = 'Administrator'
import sys
sys.path.append("D:\\framework\\zhcxkjInterfacePytest")import time
from time import sleep
import unittest2
from func.csvFileManager2 import readerimport ddt
import osimport requests
import json@ddt.ddt #在类上面加一个装饰器,说明我们的这个类是一个数据驱动的测试的类
class TestLogin3(unittest2.TestCase):table = reader("login_test_case.csv")print(table)# table=table[0]# print(table)@ddt.data(*table) #在类的上面加一个装饰器,说明我们的这个类是一个数据驱动的测试类def test_login(self,row):self.url = "https://zhcxkj.com/backend/token/login"self.userinfo={}self.userinfo={"account":row[0],"password":row[1],"forceLogin":row[2],"lang":row[3],"tenantId":row[4]}print(row[5])# 将字典类型转化为json类型self.userjson = json.dumps(self.userinfo)# 发送接口请求response = requests.post(self.url, data=self.userjson,headers={"Content-Type": "application/json;charset=UTF-8"})print(response.json())# 1、断言响应状态码print(response.status_code)print(row[5])self.assertEqual(int(row[5]), response.status_code)print(row[6])if response.json()['message'] is not None:self.assertIn(row[6], response.json()['message'])else:print(111)print("1响应状态码断言成功")# 执行测试用例
if __name__=="__main__":unittest2.TextTestRunner()
打印结果:
============================= test session starts =============================
collecting ... ../testdatafile/ind_interface/login_test_case.csv path
[['1409tenantId:soyotec:zhao_test@163.comemail', 'KZaHt2InubCNYziqF4JCGg==', '1', 'cn', '1409', '200', ''], ['1409tenantId:soyotec:zhao_test1@163.comemail', 'KZaHt2InubCNYziqF4JCGg==', '1', 'cn', '1409', '500', 'User does not exist'], ['1409tenantId:soyotec:zhao_test@163.comemail', 'KZaHt2InubCNYziqF4JCGg==1', '1', 'cn', '1409', '500', 'If the login name or password is incorrect'], ['1409tenantId:soyotec:zhao_test@163.comemail', '', '1', 'cn', '1409', '500', 'If the login name or password is incorrect'], ['', 'KZaHt2InubCNYziqF4JCGg==', '1', 'cn', '1409', '500', '操作失败,服务器异常']]
collected 5 itemstest_loginV3.py::TestLogin3::test_login_1___1409tenantId_soyotec_zhao_test_163_comemail____KZaHt2InubCNYziqF4JCGg______1____cn____1409____200______ <- ..\unixdeInterfacePytest\script\test_loginV3.py
test_loginV3.py::TestLogin3::test_login_2___1409tenantId_soyotec_zhao_test1_163_comemail____KZaHt2InubCNYziqF4JCGg______1____cn____1409____500____User_does_not_exist__ <- ..\unixdeInterfacePytest\script\test_loginV3.py
test_loginV3.py::TestLogin3::test_login_3___1409tenantId_soyotec_zhao_test_163_comemail____KZaHt2InubCNYziqF4JCGg__1____1____cn____1409____500____If_the_login_name_or_password_is_incorrect__ <- ..\unixdeInterfacePytest\script\test_loginV3.py
test_loginV3.py::TestLogin3::test_login_4___1409tenantId_soyotec_zhao_test_163_comemail________1____cn____1409____500____If_the_login_name_or_password_is_incorrect__ <- ..\unixdeInterfacePytest\script\test_loginV3.py
test_loginV3.py::TestLogin3::test_login_5_______KZaHt2InubCNYziqF4JCGg______1____cn____1409____500____操作失败_服务器异常__ <- ..\unixdeInterfacePytest\script\test_loginV3.py ======================= 5 passed, 10 warnings in 0.95s ========================Process finished with exit code 0
200
{'code': 200, 'message': None, 'data': {'access_token': '6227e889-63b2-4c10-8d31-97fa9f194bb3', 'token_type': 'bearer', 'refresh_token': '4e523eb2-eed2-4832-94b8-0be81bc9d389', 'expires_in': 43199, 'scope': 'server', 'loginHoldTime': '21600', 'sessionId': 'XpgrDCFpJlEJzvZP6E2w65JybmX1wYKHsDirCe-T'}}
200
200111
1响应状态码断言成功
PASSED500
{'code': 400, 'message': 'User does not exist', 'data': None}
500
500
User does not exist
1响应状态码断言成功
PASSED500
{'code': 400, 'message': 'If the login name or password is incorrect for 9 more times, the user will be locked for 1 minutes', 'data': None}
500
500
If the login name or password is incorrect
1响应状态码断言成功
PASSED500
{'code': 400, 'message': 'If the login name or password is incorrect for 8 more times, the user will be locked for 1 minutes', 'data': None}
500
500
If the login name or password is incorrect
1响应状态码断言成功
PASSED500
{'code': 500, 'message': '操作失败,服务器异常', 'data': None}
500
500
操作失败,服务器异常
1响应状态码断言成功
PASSED
3、Jenkins持续集成
新建一个Jenkins项目,Project zhcxkjInterfacePytest
进行配置
点击Build Now,进行执行,并生成测试报告。
执行成功,查看控制台
最后执行成功,21条通过,1个跳过。
4、生成Allure测试报告
到report下的index.html。右键Open In Browser Chrome,查看报告
可以看到,执行22条用例,测试用时4s 655ms,21条成功,1条跳过,成功率95.45%。
深圳智汇创想企业文化
企业使命:让中国智造走向世界
企业愿景:成为跨境电商行业领先者
企业价值观:尊重协作、务实高效、追求卓越、以奋斗者为本