接口测试 python 接口测试框架测试 (三)

测试小书童 · 2016年09月09日 · 最后由 测试小书童 回复于 2017年06月22日 · 1620 次阅读

基于前面的帖子优化python 接口测试框架测试报告 (二)

更新日志

  • 三层重构了整个系统
  • 实现检查参数是否必填
  • 检查参数的值类型是否正确
  • 分布图

主要代码分析

# 引用各个模块
import unittest
import time
from COMMON.BaseGoals import Goals as go
from COMMON import check

import xlsxwriter
from MODEL import Memail
from BLL import BgetEmail,BsendEmail
from BLL import BexcelReport as excel
..........

def function(self):
        temp_result = False
        hp = str_param()
        if self.index == 1: #第一个xml预留的主要是登陆
             if gm[self.index]["method"] == "POST":
                go.REALLY_RESULT = self.config_http.post(url=gm[self.index]["url"], params=hp.str__post_param(gm[self.index]["param"]))
                if go.REALLY_RESULT.get("status_code") == 200:
                    hope = ast.literal_eval(self.hope)
                    temp_result = check.compare(hope, go.REALLY_RESULT)
                    if temp_result:
                        go.LOGIN_KEY = gm[self.index]["login"]
                        print(go.LOGIN_KEY)
                        go.LOGIN_VALUE = go.REALLY_RESULT["content"][0][go.LOGIN_KEY]
                else:
                    pass
        else:
            if gm[self.index]["login"] != "0":
                    go.PARAMS[go.LOGIN_KEY] = go.LOGIN_VALUE # 登陆成功后返回过来的值,可能是token,userid等
            if gm[self.index]["method"] == "POST":
                go.PARAMS = hp.str__post_param(gm[self.index]["param"])
                go.REALLY_RESULT = self.config_http.post(gm[self.index]["url"], go.PARAMS)
            if gm[self.index]["method"] == "GET":
                go.PARAMS = hp.str_get_param(gm[self.index]["param"][0], go.PARAMS) #把登陆成功后的token,userid合并到请求参数中
                go.REALLY_RESULT = self.config_http.get(gm[self.index]["url"], go.PARAMS)
            hope = ast.literal_eval(self.hope)
            temp_result = check.compare(hope, go.REALLY_RESULT,  gm[self.index]["isList"])

        sum_test_data(temp_result) #统计
        go.CASE_TOTAL += 1


# 运行测试用例函数
def run_case(runner):
    case_list = httpbase.No
    case_list = ast.literal_eval(case_list)  # 把字符串类型的list转换为list
    if len(case_list) == False: #判断是否执行指定的用例ID
        temp_case = gm
        for index in range(1, len(temp_case)):
            test_suite = get_test_suite(index)
            runner.run(test_suite)
            # 记录运行结果
            mresult.info.append(json.loads(json.dumps(resultInfo(MresultDetail.resultInfo(), t_id=gm[index]["id"], t_name=gm[index]["name"], t_url=gm[0]["host"] +"/" + gm[index]["url"],
                       t_param=str(go.PARAMS), t_actual=go.REALLY_RESULT, t_hope=gm[index]["hope"], t_result=go.RESULT,
                       t_method=gm[index]["method"]).to_primitive())))
    else:
        for i in case_list:
            for j in range(1, len(gm)):
                if str(i) == gm[j]['id']:
                    test_suite = get_test_suite(j)
                    runner.run(test_suite)
                    # 记录运行结果
                    mresult.info.append(json.loads(json.dumps(resultInfo(MresultDetail.resultInfo(), t_id=gm[j]["id"], t_name=gm[j]["name"], t_url=gm[0]["host"] +"/"+gm[j]["url"],
                       t_param=str(go.PARAMS), t_actual=go.REALLY_RESULT, t_hope=gm[j]["hope"], t_result=go.RESULT,
                       t_method=gm[j]["method"]).to_primitive())))

  • 主要对接口参数处理
# 参数化请求
class  chttp_params():
    def __init__(self):
        pass
     # post参数化
    def str__post_param(self, list_param):
        result = {}
        for i in list_param:
            if i["must"] == "1": # 如果参数是必填
                result[i["name"]] = self.str_to(i["type"], i["value"])
        return result
    # get 参数化,param是dict
    def str_get_param(self, dict_param, param):
        result = "?"
        if dict_param["must"] == "1": # 如果参数是必填
            result += dict_param["name"] + "=" + dict_param["value"] + "&"
        return self.str_sub(0, len(result)-1, result) + "&" + self.for_dict(param)
    # 合并dict
    def for_dict(self, d):
        result = ""
        for (k, v) in d.items():
            result += str(k) + "=" + str(v)
        return result
    # 截取str
    def str_sub(self, start, end, str):
        return str[start:end]
    # 转换类型
    def str_to(self, type, s):
        elements = {
        go.INT: lambda: int(s),
        go.STR: lambda: s,
        go.FLOAT: lambda: float(s)
        }
        return elements[type]()
  • 看看我的 xml
<root>
    <title>接口测试</title>
    <host>ddd.XX.com</host>
    <port>80</port>
    <No>[1001]</No> #  不填,就是运行下面所有用例
    <header>{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","User-Agent":"Mozilla/5.0 (Windows NT 6.1; rv:29.0) Gecko/20100101 Firefox/29.0"}</header>
    <InterfaceList>
        <params>
            <name type="str">account</name>
            <value>1361212121</value>
            <must>1</must>
        </params>
        <params>
            <name type="str">password</name>
            <value>222222</value>
            <must>1</must>
        </params>
         <params>
            <name type="int">type</name>
            <value>0</value>
            <must>1</must>
        </params>
        <isList>0</isList>
        <id>1001</id>
        <name>登陆</name>
        <method>POST</method>
        <url>Login</url>
        <hope>{"appStatus":{"errorCode":0,"message":"操作成功"},"content":[{"user_sex":0,"fk_user_city":440300,"user_id":30,"nickname":"3231231","user_phone":"1857632131231759587","head_picture":"32131231","has_finance":1,"user_state":1}]}</hope>
        <login>user_id</login> # 登陆后需要返回的信息给其他接口调用,比如userid,token等
        <isList>0</isList>
    </InterfaceList>
    <InterfaceList>
      <params>
            <name type="int">lookerId</name>
            <value>2</value>
            <must>1</must>
        </params>
        <id>1002</id>
        <name>个人主页</name>
        <method>GET</method>
        <url>GetPersonalHomePage1</url>
        <hope>{"appStatus":{"errorCode":0,"message":"操作成功"},"content":[{"business_name":"坤达点子","notice_img":"\/product\/20160718184134_321.jpg","user_type":1,"user_id":2,"goods":[{"good_price":45211.0,"good_id":12,"good_name":"艾欧","banner_picture1":"\/product\/20160719165135_8977.png"},{"good_price":199.0,"good_id":14,"good_name":"麒麟瓜1","banner_picture1":"\/product\/20160720102028_5352.jpg"},{"good_price":452.0,"good_id":6,"good_name":"实力产品","banner_picture1":"\/product\/20160718165448_2602.png"},{"good_price":99898.0,"good_id":11,"good_name":"越南芒果","banner_picture1":"\/product\/20160720100057_5877.jpg"}],"shop_img":"\/product\/20160718120144_3196.jpg","head_picture":"http:\/\/dgm.boweixin.com\/\/product\/20160718134528_4744.jpg","notice_id":1}]}</hope>
         <login>1</login> # 需要登陆后的参数
        <isList>1</isList> # 有嵌套层。检查机制是,检查第一层的code,第二层list的key是否相等,list的value的值的type是否相等
    </InterfaceList>
</root>


注意这里,如果想验证这里的值的类型或者非必填参数,预期值注意变化
  <params>
            <name type="str">account</name> # type=str表示字符类型
            <value>18576759587</value>
            <must>1</must> # 1表示必填,0非必填
        </params>
  • 检查点
    • code=200
    • 参数的 must 的属性
    • 参数的 type 类型

其他

  • 当然接口测试还能做得更多,比如监控服务器
  • 后面尝试为每个参数设计一套注入 sql 模板
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 6 条回复 时间 点赞

不错, 不过 xml 里面内容多的有点难看

很好的文章,谢谢分享!

up 一下,最近领导非得让我做一个 python 版的接口工具,借鉴了一下版主的工具🤐

看起来好复杂,我使用 python 的第三方库 requests,这个很方便了

楼主你好,运行 runner_m.py 时是个空测试套件,也就是说 if name == 'main': 下面的代码就不会跑,这是什么原因?

尹全旺 回复

这个框架我已经不使用和维护,如果感兴趣,可以参考我另外一篇帖子:https://testerhome.com/topics/9044

测试小书童 关闭了讨论 06月22日 14:22
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册