智汇创想pytest接口自动化测试框架
本测试框架是基于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 unittest2
import 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 item
test_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 items
test_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 unittest2
import 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 items
test_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 item
test_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 unittest2
import 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 item
test_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 unittest2
import 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 item
test_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 unittest2
import 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)
# 定义一个函数,实现使用正确的用户名密码登录,最后需要进行断言,获取登录用户名判断是否为预期的zhaodahai
def 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 items
test_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 reader
import ddt
import os
import 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 items
test_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
200
111
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%。
深圳智汇创想企业文化
企业使命:让中国智造走向世界
企业愿景:成为跨境电商行业领先者
企业价值观:尊重协作、务实高效、追求卓越、以奋斗者为本