美文网首页JmeterpythonCI
自己驱动自己—Python代码写接口测试(一)

自己驱动自己—Python代码写接口测试(一)

作者: 点点寒彬 | 来源:发表于2016-10-25 20:57 被阅读888次
    20161021

    背景

    《聊聊接口测试》中我提到了使用Jmeter的问题和局限性。

    这里其实是有一个问题的。Jmeter的学习成本其实挺大的,基础的发请求断言这类功能当然是很简单,再往后,很多细节上的处理问题,解决起来就非常非常困难,网络上很难找到类似的问题和解决方法,即使是自己去翻官方文档,也不一定就能很快的找到。

    那自己写一个接口测试就迫在眉睫了,本着自己驱动自己的想法,我直接把所有内容写在代码中,自己维护起来也很快。

    环境


    版本相关

    操作系统:Mac OS X EI Caption

    Python版本:3.6

    IDE:PyCharm

    第三方依赖库:requests

    前端:Bootstrap

    可视化:Echarts


    思路

    这部分主要参考Jmeter的方法。先执行接口测试,然后收集执行结果,写到一个结果文件中,再用脚本去读这个结果文件,生成结果报告。Jmeter是使用xml的方式生成一个jmx的结果,我对JSON熟悉一些,就使用JSON来生成结果文件。

    测试报告

    报告展示报告展示 报告展示2报告展示2

    整体架构

    |____Common.py
    |____Debug.py
    |____NewLive.py
    |____outReport.py
    |____report.html
    |____reportData.json
    |____Run.py
    

    Common.py封装了一些通用的方法,为以后拓展多个项目做准备。

    Debug.py是用于编写单条接口测试用例的文件,基于Pycharm对unittest的友好支持,调试起来非常方便。

    NewLive.py是我的接口测试文件,里面放了所有的接口测试用例、执行方法和生成结果文件的方法。

    outReport.py是读取结果文件生成HTML测试报告的脚本

    report.html是测试报告。

    reportData.json是接口测试文件生成的结果文件。

    Run.py是启动器,运行后就会批量执行接口测试。

    注意:本工程只适用于单个接口测试项目,如果有多个接口测试项目,则需要增加一些遍历的方法。

    接口测试文件

    这个文件是每一个接口测试项目的核心文件,整个项目的所有接口测试用例和执行方法都在这里面。

    项目的每一个接口,都写一个类。这个接口的测试用例,在这个类中都以test开头。

    使用unittest作为框架本是最方便的方法,无奈unittest方法对于结果文件的写入不方便,我又懒得去翻官方文档,于是简单的自己写一个启动方法。

    run方法

    def run(classInstance):
        """
        执行类中的所有以test开头的方法,前提是初始化的内容要与类中的name属性一致
        :param classInstance:类
        :return:None
        """
        funcs = []
        for x in dir(classInstance):
            if x.startswith('test'):
                funcs.append(x)
        for x in funcs:
            eval(classInstance.name+'.'+x+'()')
    

    这个方法是启动测试的实现方法,run()方法需要传入一个类作为参数,方法中需要获取这个类中的name属性用来启动类中的测试用例,因此需要在类中专门定义这个name属性,并且实例化的时候需要与这个name属性一致。

    接口类

    class StartLive:
        def __init__(self):
            self.classes = []
            self.name = 'startlive'
            InterFaceInfo = {
                'InterFaceName': 'StartLive',
                'FuncNo': 'xxx',
                'Desc': 'xxx'
            }
            self.classes.append(InterFaceInfo)
    

    接口类的初始化需要定制一些内容。

    self.classes列表用于收集这个接口的测试情况。

    self.name需要与实例化的名称一致,用于启动测试。

    InterFaceInfo说明接口的描述,方便测试报告展示。

    测试用例

    def test001_StartLiveCommon(self):
            """正常开始直播"""
            payload = {
                "funcNo": "XXX",
                "roomId": "XXX",
                "userId": "XXX",
                "broadIssue": time.strftime("%H%m%d") + "直播开始",
                "broadNotice": time.strftime("%H%m%d") + "直播开始",
            }
    
            r = requests.post(url, data=payload)
            result = r.json()
    
            try:
                assert result['error_no'] == '0'
                assert result['error_info'] == '创建直播并发布直播公告成功'
                consequence = "success"
            except Exception:
                consequence = 'error'
    
            rst_data = {
                "Url": url,
                "desc": "正常开始直播",
                "sendData": payload,
                "rspData": result,
                "result": consequence
            }
            self.classes.append(rst_data)
    

    由于之前的run()方法是遍历以test开头的方法,因此用例的方法的命名必须以test开头。

    第一部分的payload是请求的参数,第二部分是请求的方法,可以根据自己的需求使用get或者post方法。第三部分是断言部分,断言成功则给一个成功的标记,断言失败则给一个失败的标记。第四部分是测试结果的收集,信息包括url、案例描述、发送数据、接受数据和测试结果,用于最终报告的展示。第五部分就是把这个结果放到接口类初始化时候的容器中。

    清理方法

    def testTearClass(self):
            reportElement.append(self.classes)
    

    在执行完毕之后需要做一下数据收集,因此把初始化中的容器self.classes列表的内容放到reportElement这个大容器中。

    注意:这个方法必须放在类的最后,确保这个方法是最后一个被执行的,也就确保了所有的测试结果数据都能被收集,当然,由于要被run()方法执行到,因此命名也必须以test开头

    写结果文件

    if __name__ == '__main__':
        startlive = StartLive()
        run(startlive)
    
        with codecs.open('reportData.json', 'w', 'utf-8') as f:
            data = json.dumps(reportElement, sort_keys=True, indent=4)
            f.write(data)
    

    最终文件的执行需要将类初始化,然后在run()方法中传入这个初始化的类,run()方法就会自动执行所有的测试用例,将结果全部归集到reportElement这个容器中。

    再调用写json文件的方法把结果文件写出来。

    生成测试报告

    生成测试报告的核心就是去遍历这个JSON文件的内容。

    def exportReport(jsonName):
        """
        根据结果报告的JSON文件生成HTML报告
        :param jsonName:{str}JSON文件名
        :return:None
        """
        tableHead = []
        trs = []
        table = []
        global interFaceName
        with open(jsonName, 'r') as f:
            jsonData = json.loads(f.read())
    
        for x in jsonData:  # x表示每个接口的数据
            trbody = []
            for i, a in enumerate(x):
                if i == 0:
                    interFaceName = a['InterFaceName']
                    tableHead.append(exportInterfaceTableHead(
                        "接口名称: {0}, 接口描述: {1}, 功能号: {2}".format(a['InterFaceName'], a['Desc'], a['FuncNo'])))
                else:
                    trbody.append(
                        exportTableTr(interFaceName + str(i), a['desc'], a['result'], a['sendData'], a['rspData'],
                                      a['Url']))
            trs.append(''.join(trbody))
    
        for x, y in zip(tableHead, removeEmptyInList(trs)):
            table.append(x + y + exportBottom())
    
        interFaceTable = ''.join(table)
        html = htmlHead('直播接口测试', dashBoardTable(exportDashBoardTable(jsonName))) + interFaceTable + htmlFoot(jsonName)
        with codecs.open('report.html', 'w', 'utf-8') as f:
            f.write(html)
    

    生成HTML结果的最优方式,肯定是用Django来做一个小后台,这样可以用模板引擎来来处理HTML,更加快速和灵活。不过为了懒得折腾后台,在整个生成结果的方法中,我用的是硬编码的方式,也就是说我把html的内容全部以字符串的形式放在代码中。然后用format方法把一些遍历的结果放到字符串中,最终把所有的字符串全部拼接到一起,直接写到文件中,就生成了最终的测试报告。

    大部分前端展示的内容,都是使用Bootstrap来处理,比较简单直观。饼状图使用的是百度Echarts。

    最后

    这只是一个初步的结果,后期在项目增加时,需要做一些改造,比如测试报告的归档,测试用例的归档等内容,执行方法的优化等等。

    相关文章

      网友评论

      本文标题:自己驱动自己—Python代码写接口测试(一)

      本文链接:https://www.haomeiwen.com/subject/potduttx.html