Python测开28期-偕行-har生成接口测试用例

一、Har简介

  • Har格式是指HTTP归档格式(HTTP Archive Format)。
  • 用于记录HTTP会话信息的文件格式。
  • 多个浏览器都可以生成 Har 格式的数据。

二、应用场景

  • 通过 Har 格式的接口数据,转换为接口自动化测试脚本:
    • 提升脚本的编写效率;
    • 降低脚本的出BUG的几率;

三、实现思路

  1. 读取Har数据,获取到request内容。
  2. 提前准备测试用例模版,读取模板文件,将模板中的数据进行替换。
  3. 将读取的Har数据写入到模板中,替换后的模板写入测试用例文件。

四、模板技术

1、什么是Mustache

  • Mustache是一种轻量级的模板语言。

  • 需要定义模板,然后可以将数据填充到设定好的位置。

  • 官网地址:https://mustache.github.io/

  • python的第三方库:

    • pystache:pip install pystache
    • chevron:pip install chevron;–更推荐使用: chevron is fast Chevron runs in less than half the time of pystache (Which is not even up to date on the spec). And in about 70% the time of Stache (A ‘trimmed’ version of mustache, also not spec compliant).

2、模板技术使用

  • pystache库:pystache.render("origin_data",{"key":"value"}

  • chevron库:chevron.render("origin_data",{"key":"value"}

  • 参数说明:

    • 参数一:使用{{key}}占位的字符串数据;
    • 参数二:需要替换进去的键值对数据,key为占位的变量,value为需要替换进去的值;

五、使用har生成接口测试用例

1、常用模板

(1)Junit接口测试用例模板

package com.ceshiren.har;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
public class HttpbinTest {
    @Test
    void httpbinReq() {
        given()
                // 可以设置测试预设
                .when()
                // 发起 GET 请求
                .get("{{url}}")
                .then()
                // 解析结果
                .log().all()  // 打印完整响应信息
                .statusCode(200);  // 响应断言
    }
}

(2)httprunner 的用例模版

config:
    name: basic test with httpbin
teststeps:
-
    name: httprunner的模板
    request:
        url: {{url}}
        method: GET
    validate_script:
        - "assert status_code == 200"

3、python 接口测试用例模板

import requests
def test_request():
    r = requests.get(url="{{url}}")

2、生成python(pytest)接口测试用例模板

  1. 读取Har数据,获取到request内容。
  2. 提前准备测试用例模版,读取模板文件,将模板中的数据进行替换。
  3. 将读取的Har数据写入到模板中,替换后的模板写入测试用例文件。

pytest.template

import requests

def test_case_{{title}}():
    # 发起请求,json参数根据实际情况自行传入参数,get请求用params传入,post请求如果是formdata用data传入,如果是json就用json传入
    response = requests.request(method="{{method}}",url="{{url}}",json=)
    
    # 断言-状态码
    assert response.status_code == 200

har2case.py

import json
import chevron
from jsonpath import jsonpath

class GenerateCase:

    # 读取har文件获取到request内容
    def __load_har(self,har_filename):
        with open(har_filename,'r',encoding='utf8') as f:
            har_dict = json.load(f)
        # 返回request内容
        return jsonpath(har_dict,"$..request")[0]

    # 以har中数据替换模板中的变量并以模板生成测试用例
    def generate_case_by_template(self,template_filename,case_filename,har_filename):
        # 1、获取har中的request数据
        request_data = self.__load_har(har_filename)
        method = request_data["method"]
        url = request_data["url"]
        title = url.split("/")[len(url.split("/"))-1]
        # title = url.
        # 2、读取模板文件,将模板中的数据进行替换
        with open(template_filename,'r',encoding='utf8') as f:
            template = f.read()
        # 替换
        case_content = chevron.render(template,{"method":method,"url":url,"title":title})
        # 3、替换后的模板写入测试用例文件
        with open(case_filename,'w',encoding='utf8') as f:
            f.write(case_content)

if __name__ == '__main__':
    har_filename = "../data/litemall.hogwarts.ceshiren.com.har"
    case_filename = "../testcase/test_login.py"
    template_filename = "../data/pytest.template"
    GenerateCase().generate_case_by_template(template_filename,case_filename,har_filename)

litemall.hogwarts.ceshiren.com.har

{
  "log": {
    "version": "1.2",
    "creator": {
      "name": "WebInspector",
      "version": "537.36"
    },
    "pages": [],
    "entries": [
      {
        "_initiator": {
          "type": "script",
          "stack": {
            "callFrames": [
              {
                "functionName": "",
                "scriptId": "10",
                "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/chunk-27643b19.a4fcf60f.js",
                "lineNumber": 0,
                "columnNumber": 22235
              },
              {
                "functionName": "xhr",
                "scriptId": "10",
                "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/chunk-27643b19.a4fcf60f.js",
                "lineNumber": 0,
                "columnNumber": 19825
              },
              {
                "functionName": "lt",
                "scriptId": "10",
                "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/chunk-27643b19.a4fcf60f.js",
                "lineNumber": 0,
                "columnNumber": 23252
              }
            ],
            "parent": {
              "description": "Promise.then",
              "callFrames": [
                {
                  "functionName": "request",
                  "scriptId": "10",
                  "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/chunk-27643b19.a4fcf60f.js",
                  "lineNumber": 0,
                  "columnNumber": 26854
                },
                {
                  "functionName": "",
                  "scriptId": "10",
                  "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/chunk-27643b19.a4fcf60f.js",
                  "lineNumber": 0,
                  "columnNumber": 180
                },
                {
                  "functionName": "Mt",
                  "scriptId": "10",
                  "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/chunk-27643b19.a4fcf60f.js",
                  "lineNumber": 0,
                  "columnNumber": 31509
                },
                {
                  "functionName": "login",
                  "scriptId": "72",
                  "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/chunk-63ca1188.7c7a066f.js",
                  "lineNumber": 0,
                  "columnNumber": 5158
                },
                {
                  "functionName": "loginSubmit",
                  "scriptId": "72",
                  "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/chunk-63ca1188.7c7a066f.js",
                  "lineNumber": 0,
                  "columnNumber": 5458
                },
                {
                  "functionName": "c",
                  "scriptId": "9",
                  "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/app.3b7a29df.js",
                  "lineNumber": 28,
                  "columnNumber": 86885
                },
                {
                  "functionName": "k",
                  "scriptId": "9",
                  "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/app.3b7a29df.js",
                  "lineNumber": 28,
                  "columnNumber": 84859
                },
                {
                  "functionName": "Qe",
                  "scriptId": "9",
                  "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/app.3b7a29df.js",
                  "lineNumber": 12,
                  "columnNumber": 20570
                },
                {
                  "functionName": "n",
                  "scriptId": "9",
                  "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/app.3b7a29df.js",
                  "lineNumber": 12,
                  "columnNumber": 10794
                },
                {
                  "functionName": "Ci.i._wrapper",
                  "scriptId": "9",
                  "url": "https://litemall.hogwarts.ceshiren.com/vue/static/js/app.3b7a29df.js",
                  "lineNumber": 12,
                  "columnNumber": 56949
                }
              ]
            }
          }
        },
        "_priority": "High",
        "_resourceType": "xhr",
        "cache": {},
        "connection": "954403",
        "request": {
          "method": "POST",
          "url": "https://litemall.hogwarts.ceshiren.com/wx/auth/login",
          "httpVersion": "http/2.0",
          "headers": [
            {
              "name": ":authority",
              "value": "litemall.hogwarts.ceshiren.com"
            },
            {
              "name": ":method",
              "value": "POST"
            },
            {
              "name": ":path",
              "value": "/wx/auth/login"
            },
            {
              "name": ":scheme",
              "value": "https"
            },
            {
              "name": "accept",
              "value": "application/json, text/plain, */*"
            },
            {
              "name": "accept-encoding",
              "value": "gzip, deflate, br"
            },
            {
              "name": "accept-language",
              "value": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"
            },
            {
              "name": "cache-control",
              "value": "no-cache"
            },
            {
              "name": "content-length",
              "value": "43"
            },
            {
              "name": "content-type",
              "value": "application/json"
            },
            {
              "name": "cookie",
              "value": "_ga=GA1.2.123742433.1644288262; sensorsdata2015jssdkcross=%7B%22%24device_id%22%3A%221888985fce60-03d79ec7b95907-7b515473-1327104-1888985fce7fad%22%7D; Hm_lvt_214f62eef822bde113f63fedcab70931=1696156377,1696377764,1696997968,1697074446; _ga_L943NTQ6FJ=GS1.2.1697440574.2.0.1697440574.60.0.0; JSESSIONID=91f733ad-8c18-4142-86cd-08b08dd81c25; _gid=GA1.2.348187596.1697553224; Hm_lpvt_214f62eef822bde113f63fedcab70931=1697696055; _ga_XP6GNLH30P=GS1.2.1697696060.83.1.1697698552.0.0.0"
            },
            {
              "name": "origin",
              "value": "https://litemall.hogwarts.ceshiren.com"
            },
            {
              "name": "pragma",
              "value": "no-cache"
            },
            {
              "name": "referer",
              "value": "https://litemall.hogwarts.ceshiren.com/vue/index.html"
            },
            {
              "name": "sec-fetch-dest",
              "value": "empty"
            },
            {
              "name": "sec-fetch-mode",
              "value": "cors"
            },
            {
              "name": "sec-fetch-site",
              "value": "same-origin"
            },
            {
              "name": "user-agent",
              "value": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/115.0.0.0"
            },
            {
              "name": "x-litemall-token",
              "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0aGlzIGlzIGxpdGVtYWxsIHRva2VuIiwiYXVkIjoiTUlOSUFQUCIsImlzcyI6IkxJVEVNQUxMIiwiZXhwIjoxNjk3MjU3NzU3LCJ1c2VySWQiOjQwOTk2OSwiaWF0IjoxNjk3MjUwNTU3fQ.hm4pFgM--OzVLbeDgTy26-aFIHUvqCkfzyyp804JE3A"
            }
          ],
          "queryString": [],
          "cookies": [
            {
              "name": "_ga",
              "value": "GA1.2.123742433.1644288262",
              "path": "/",
              "domain": ".ceshiren.com",
              "expires": "2024-11-22T06:14:16.174Z",
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "sensorsdata2015jssdkcross",
              "value": "%7B%22%24device_id%22%3A%221888985fce60-03d79ec7b95907-7b515473-1327104-1888985fce7fad%22%7D",
              "path": "/",
              "domain": ".ceshiren.com",
              "expires": "2024-11-22T06:07:54.029Z",
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "Hm_lvt_214f62eef822bde113f63fedcab70931",
              "value": "1696156377,1696377764,1696997968,1697074446",
              "path": "/",
              "domain": ".ceshiren.com",
              "expires": "2024-10-18T06:14:15.000Z",
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "_ga_L943NTQ6FJ",
              "value": "GS1.2.1697440574.2.0.1697440574.60.0.0",
              "path": "/",
              "domain": ".ceshiren.com",
              "expires": "2024-11-19T07:16:14.386Z",
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "JSESSIONID",
              "value": "91f733ad-8c18-4142-86cd-08b08dd81c25",
              "path": "/",
              "domain": "litemall.hogwarts.ceshiren.com",
              "expires": "1969-12-31T23:59:59.000Z",
              "httpOnly": true,
              "secure": false,
              "sameSite": "Lax"
            },
            {
              "name": "_gid",
              "value": "GA1.2.348187596.1697553224",
              "path": "/",
              "domain": ".ceshiren.com",
              "expires": "2023-10-20T06:14:16.000Z",
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "Hm_lpvt_214f62eef822bde113f63fedcab70931",
              "value": "1697696055",
              "path": "/",
              "domain": ".ceshiren.com",
              "expires": "1969-12-31T23:59:59.000Z",
              "httpOnly": false,
              "secure": false
            },
            {
              "name": "_ga_XP6GNLH30P",
              "value": "GS1.2.1697696060.83.1.1697698552.0.0.0",
              "path": "/",
              "domain": ".ceshiren.com",
              "expires": "2024-11-22T06:55:52.574Z",
              "httpOnly": false,
              "secure": false
            }
          ],
          "headersSize": -1,
          "bodySize": 43,
          "postData": {
            "mimeType": "application/json",
            "text": "{\"username\":\"user123\",\"password\":\"user123\"}"
          }
        },
        "response": {
          "status": 200,
          "statusText": "OK",
          "httpVersion": "http/2.0",
          "headers": [
            {
              "name": "access-control-allow-credentials",
              "value": "true"
            },
            {
              "name": "access-control-allow-origin",
              "value": "https://litemall.hogwarts.ceshiren.com"
            },
            {
              "name": "content-encoding",
              "value": "gzip"
            },
            {
              "name": "content-type",
              "value": "application/json;charset=UTF-8"
            },
            {
              "name": "date",
              "value": "Thu, 19 Oct 2023 07:29:59 GMT"
            },
            {
              "name": "server",
              "value": "CBS"
            },
            {
              "name": "vary",
              "value": "accept-encoding,origin,access-control-request-headers,access-control-request-method,accept-encoding"
            }
          ],
          "cookies": [],
          "content": {
            "size": 436,
            "mimeType": "application/json",
            "text": "{\"errno\":0,\"data\":{\"userInfo\":{\"nickName\":\"user123\",\"avatarUrl\":\"https://yanxuan.nosdn.127.net/80841d741d7fa3073e0ae27bf487339f.jpg?imageView&quality=90&thumbnail=64x64\"},\"token\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0aGlzIGlzIGxpdGVtYWxsIHRva2VuIiwiYXVkIjoiTUlOSUFQUCIsImlzcyI6IkxJVEVNQUxMIiwiZXhwIjoxNjk3NzA3ODAwLCJ1c2VySWQiOjQwOTk2OSwiaWF0IjoxNjk3NzAwNjAwfQ.hlMFoTvBAdPlDzUzYZHzqdVCOZIF_52468EPEgFEjyg\"},\"errmsg\":\"成功\"}"
          },
          "redirectURL": "",
          "headersSize": -1,
          "bodySize": -1,
          "_transferSize": 642,
          "_error": null
        },
        "serverIPAddress": "182.92.156.22",
        "startedDateTime": "2023-10-19T07:29:59.580Z",
        "time": 170.59899994637817,
        "timings": {
          "blocked": 1.126999993801117,
          "dns": -1,
          "ssl": -1,
          "connect": -1,
          "send": 0.477,
          "wait": 168.6680000237748,
          "receive": 0.3269999288022518,
          "_blocked_queueing": 0.5189999938011169
        }
      }
    ]
  }
}

test_login.py

import requests

def test_case_login():
    # 发起请求,json参数根据实际情况自行传入参数,get请求用params传入,post请求如果是formdata用data传入,如果是json就用json传入
    response = requests.request(method="POST",url="https://litemall.hogwarts.ceshiren.com/wx/auth/login",json=)
    
    # 断言-状态码
    assert response.status_code == 200