Httprunner框架學習1--基本使用

1.Httprunner簡介

官網https://testerhome.com/opensource_projects/httprunner

HttpRunner 是一款面向 HTTP(S) 協議的通用測試框架,只需編寫維護一份YAML/JSON腳本,即可實現自動化測試、性能測試、線上監控、持續集成等多種測試需求。

  • 繼承 Requests 的全部特性,輕鬆實現 HTTP(S) 的各種測試需求
  • 測試用例與代碼分離,採用YAML/JSON的形式描述測試場景,保障測試用例具備可維護性
  • 測試用例支持分層機制,充分實現測試用例的複用
  • 測試用例支持參數化和數據驅動機制
  • 使用 skip 機制實現對測試用例的分組執行控制
  • 支持熱加載機制,在文本測試用例中輕鬆實現複雜的動態計算邏輯
  • 基於 HAR 實現接口錄製和用例生成功能(har2case
  • 結合 Locust 框架,無需額外的工作即可實現分佈式性能測試
  • 執行方式採用 CLI 調用,可與 Jenkins 等持續集成工具完美結合
  • 測試結果統計報告簡潔清晰,附帶詳盡統計信息和日誌記錄
  • 具有可擴展性,便於擴展實現 Web 平臺化(HttpRunnerManager

2.環境搭建

pip install httprunner

3.基本使用介紹

httprunner主要是通過YAML或JSON形式描述各種測試用例的,當你有了YAML或JSON格式的測試用例後,只需執行

hrun xxx.yml,或hrun xxx.json,即可執行測試用例

所以學習httprunner主要是編寫yml或json格式的測試用例

yml或json格式的用例有兩種方法獲取1.自己編寫2.通過抓包,使用har2case工具轉換獲得

先來一個簡單的錄製獲取用例的demo

1.準備api_server.py,這個是一個flask框架編寫的接口文件,需要先安裝flask框架,

import hashlib
import hmac
import json
import random
import string
from functools import wraps

from flask import Flask, make_response, request

SECRET_KEY = "DebugTalk"

app = Flask(__name__)

""" storage all users' data
data structure:
    users_dict = {
        'uid1': {
            'name': 'name1',
            'password': 'pwd1'
        },
        'uid2': {
            'name': 'name2',
            'password': 'pwd2'
        }
    }
"""
users_dict = {}

""" storage all token data
data structure:
    token_dict = {
        'device_sn1': 'token1',
        'device_sn2': 'token1'
    }
"""
token_dict = {}


def gen_random_string(str_len):
    """ generate random string with specified length
    """
    return ''.join(
        random.choice(string.ascii_letters + string.digits) for _ in range(str_len))

def get_sign(*args):
    content = ''.join(args).encode('ascii')
    sign_key = SECRET_KEY.encode('ascii')
    sign = hmac.new(sign_key, content, hashlib.sha1).hexdigest()
    return sign

def gen_md5(*args):
    return hashlib.md5("".join(args).encode('utf-8')).hexdigest()


def validate_request(func):

    @wraps(func)
    def wrapper(*args, **kwargs):
        device_sn = request.headers.get('device_sn', "")
        token = request.headers.get('token', "")

        if not device_sn or not token:
            result = {
                'success': False,
                'msg': "device_sn or token is null."
            }
            response = make_response(json.dumps(result), 401)
            response.headers["Content-Type"] = "application/json"
            return response

        if token_dict.get(device_sn) != token:
            result = {
                'success': False,
                'msg': "Authorization failed!"
            }
            response = make_response(json.dumps(result), 403)
            response.headers["Content-Type"] = "application/json"
            return response

        return func(*args, **kwargs)

    return wrapper


@app.route('/')
def index():
    return "Hello World!"

@app.route('/api/get-token', methods=['POST'])
def get_token():
    device_sn = request.headers.get('device_sn', "")
    os_platform = request.headers.get('os_platform', "")
    app_version = request.headers.get('app_version', "")
    data = request.get_json()
    sign = data.get('sign', "")

    expected_sign = get_sign(device_sn, os_platform, app_version)

    if expected_sign != sign:
        result = {
            'success': False,
            'msg': "Authorization failed!"
        }
        response = make_response(json.dumps(result), 403)
    else:
        token = gen_random_string(16)
        token_dict[device_sn] = token

        result = {
            'success': True,
            'token': token
        }
        response = make_response(json.dumps(result))

    response.headers["Content-Type"] = "application/json"
    return response

@app.route('/api/users')
@validate_request
def get_users():
    users_list = [user for uid, user in users_dict.items()]
    users = {
        'success': True,
        'count': len(users_list),
        'items': users_list
    }
    response = make_response(json.dumps(users))
    response.headers["Content-Type"] = "application/json"
    return response

@app.route('/api/reset-all')
@validate_request
def clear_users():
    users_dict.clear()
    result = {
        'success': True
    }
    response = make_response(json.dumps(result))
    response.headers["Content-Type"] = "application/json"
    return response

@app.route('/api/users/<int:uid>', methods=['POST'])
@validate_request
def create_user(uid):
    user = request.get_json()
    if uid not in users_dict:
        result = {
            'success': True,
            'msg': "user created successfully."
        }
        status_code = 201
        users_dict[uid] = user
    else:
        result = {
            'success': False,
            'msg': "user already existed."
        }
        status_code = 500

    response = make_response(json.dumps(result), status_code)
    response.headers["Content-Type"] = "application/json"
    return response

@app.route('/api/users/<int:uid>')
@validate_request
def get_user(uid):
    user = users_dict.get(uid, {})
    if user:
        result = {
            'success': True,
            'data': user
        }
        status_code = 200
    else:
        result = {
            'success': False,
            'data': user
        }
        status_code = 404

    response = make_response(json.dumps(result), status_code)
    response.headers["Content-Type"] = "application/json"
    return response

@app.route('/api/users/<int:uid>', methods=['PUT'])
@validate_request
def update_user(uid):
    user = users_dict.get(uid, {})
    if user:
        user = request.get_json()
        success = True
        status_code = 200
        users_dict[uid] = user
    else:
        success = False
        status_code = 404

    result = {
        'success': success,
        'data': user
    }
    response = make_response(json.dumps(result), status_code)
    response.headers["Content-Type"] = "application/json"
    return response

@app.route('/api/users/<int:uid>', methods=['DELETE'])
@validate_request
def delete_user(uid):
    user = users_dict.pop(uid, {})
    if user:
        success = True
        status_code = 200
    else:
        success = False
        status_code = 404

    result = {
        'success': success,
        'data': user
    }
    response = make_response(json.dumps(result), status_code)
    response.headers["Content-Type"] = "application/json"
    return response
if __name__ == '__main__':
    app.run()

直接運行後,訪問http://127.0.0.1:5000/

使用fiddler抓包後,

selected Sessions,選擇httpArchive v1.1,導出爲test.har

2.使用har2case將har文件轉換爲yml或json格式

不加 -2y參數默認轉換爲json格式,加了後是yml格式

test.json

{
    "teststeps": [
        {
            "validate": [
                {
                    "eq": [
                        "status_code", 
                        200
                    ]
                }, 
                {
                    "eq": [
                        "headers.Content-Type", 
                        "text/html; charset=utf-8"
                    ]
                }
            ], 
            "request": {
                "url": "http://127.0.0.1:5000/", 
                "headers": {
                    "User-Agent": "Fiddler"
                }, 
                "method": "GET"
            }, 
            "name": "/"
        }
    ], 
    "config": {
        "variables": {}, 
        "name": "testcase description"
    }
}

test.yml

config:
    name: testcase description
    variables: {}
teststeps:
-   name: !!python/unicode '/'
    request:
        headers:
            !!python/unicode 'User-Agent': !!python/unicode 'Fiddler'
        method: !!python/unicode 'GET'
        url: !!python/unicode 'http://127.0.0.1:5000/'
    validate:
    -   eq:
        - status_code
        - 200
    -   eq:
        - headers.Content-Type
        - !!python/unicode 'text/html; charset=utf-8'

生成的就是測試用例了,然後使用命令進行運行,

可以查看生成的報告

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章