Jmeter输出报告转allure2

最近发现公司很多是jmeter进行的自动化测试,存在的问题:原生报告巨丑无比,并且还没有那么友好的展示详情。

话不多说,开搞。

首先是jmeter配置的调整,需要拿到整个请求的详情

1、找到jmeter bin目录下的jmeter.properties修改配置如下


2、找到jmeter bin目录下的修改user.properties添加配置

jmeter.save.saveservice.output_format=xml

jmeter.save.saveservice.response_data=true

jmeter.save.saveservice.samplerData=true

jmeter.save.saveservice.requestHeaders=true

jmeter.save.saveservice.url=true

jmeter.save.saveservice.responseHeaders=true

3、通过/u01/jmeter/apache-jmeter-5.3/bin/jmeter.sh -n -t xxx.jmx -l result.xml -j test.log 输出报告


这个时候就会发现输出的xml报告包含了用例的层级和详情信息

t表示从请求开始到响应结束的时间

lt表示整个的空闲时间

ts表示访问的时刻

s表示返回的结果true表示成功,false表示失败

lb表示标题

rc表示返回的响应码

rm表示响应信息

tn表示线程的名字“1-138”表示第1个线程组的第138个线程。

dt表示响应的文件类型

by表示请求和响应的字节数

到这里差不多完成一半了,有这个xml,我把它解析成自己想要的pytest allure不就行了

4、把xml报告处理成pytest,python3代码如下

        #通过命令行来执行 ,例如python3 dealReportXml.py result.xml test_demo.py report/resource

# -*- coding: utf-8 -*-

# @Time    : 2020/11/30 4:29 下午

import xml.etree.cElementTreeas ET

import json,os,uuid

import sys

# xmlObject xml工程

# checkString 这个其实是固定值 httpSample,只不过后面想要获取其他结构参数化

# num 当时想嵌套多层,后来发现allure只三层结构,其实这个也没啥用

# result 传递解析的xml

# demoFile 生成的pytes文件

# featureIndex 用来排序参数用例,按照jmeter中的树结果

# storyIndex 同上,是第二层级的排序

def checkChildren(xmlObject, checkString, num, result, demoFile, featureIndex, storyIndex):

    for childrenin xmlObject:

        try:

            if num == 1 and children.attrib['sby'] != "0":

                featureIndexStr='#'+str(featureIndex)+" " if featureIndex >= 10 else '#0'+str(featureIndex)+" "

                result["feature"] = featureIndexStr+children.attrib['lb']

                featureIndex += 1

            if num >= 2 and children.tag== "sample":

                storyIndexStr= '#' + str(storyIndex) + " " if storyIndex >= 10 else '#0' + str(

                    storyIndex) + " "

                result["story"] = storyIndexStr+children.attrib['lb']

                storyIndex += 1

        except:

            pass

        if children.tag== checkString:

            result['case_name'] = children.attrib['lb']

            for httpSampleChildrenin children:

                result[httpSampleChildren.tag] = httpSampleChildren.text

if httpSampleChildren.tag== 'assertionResult':

                    for assertionResultChildrenin httpSampleChildren:

                        result[assertionResultChildren.tag] = assertionResultChildren.text

feature= result['feature'] if "feature" in result else None

            story= result['story'] if 'story' in result else None

            case_name= result['case_name'] if 'case_name' in result else None

            URL= result['java.net.URL'] if 'java.net.URL' in result else None

            method= result['method'] if 'method' in result else None

            requestHeader= result['requestHeader'] if 'requestHeader' in result else None

            queryString= result['queryString'] if 'queryString' in result else None

            responseData= result['responseData'] if 'responseData' in result else None

            failureMessage= result['failureMessage'] if 'failureMessage' in result else None

            failure= result['failure'] if 'failure' in result else "false"

            print(feature,story,case_name,failureMessage,URL)

            storyString= "@allure.story('"+result['story']+"')  # 二级目录" if 'story' in result else ''

            pyString= '''

@allure.feature('{feature}')  # 一级目录{story}

@allure.title("{case_name}")

def test_allure_report_{num}():

    with allure.step('请求url:{URL}'):

        print('请求url:{URL}')

    with allure.step('请求方法:{method}' ):

        print('请求方法:{method}' )

    with allure.step('请求头:{requestHeader}' ):

        print('请求头:{requestHeader}' )

    with allure.step(\'''请求数据:{queryString}\'''):

        print(\'''请求数据:{queryString}\''')

    with allure.step('接口返回:{responseData}'):

        print('接口返回:{responseData}')

    with allure.step('断言结果:{failureMessage}'):

        print('断言结果:{failureMessage}')

    assert "{failure}" == 'false' '''.format(feature=feature,story=storyString,case_name=case_name,

                                            num=str(uuid.uuid1()).replace('-',''),

                                          URL=URL,method=method, requestHeader=str(requestHeader).replace('\n', '').replace('\r', ''),

                                            queryString=str(json.dumps(queryString)).replace("'","\""),

                                            responseData=str(json.dumps(responseData)).replace("'","\""),

                                          failureMessage=str(failureMessage).replace("'","\""),failure=failure)

            print(pyString)

            with open(demoFile,'a') as c:

                c.write(pyString)

        else:

            checkChildren(children,checkString,num+1,result,demoFile,featureIndex,storyIndex)

if __name__== '__main__':

    #通过命令行来执行 ,例如python3 dealReportXml.py result.xml test_demo.py report/resource

    commonndLines= sys.argv

print(commonndLines)

    with open(commonndLines[2], "w") as demo:

        demo.write('''

# -*- coding: utf-8 -*-

import allure

            ''')

    tree= ET.parse(commonndLines[1])

    root= tree.getroot()

    checkChildren(root,"httpSample",1,{},commonndLines[2],1,1)

    pyString= 'pytest --capture=no '+commonndLines[2]+' --alluredir '+commonndLines[3]

    os.system(pyString)

    alSring= "allure generate "+commonndLines[3]+" -o report/html --clean"

    os.system(alSring)

5、打开生成的报告


细心的你会发现,这里面的时间是错误的,别急,我们来处理一下。

回头看看jmeter报告中的协议

t表示从请求开始到响应结束的时间

lt表示整个的空闲时间

ts表示访问的时刻

s表示返回的结果true表示成功,false表示失败

lb表示标题

rc表示返回的响应码

rm表示响应信息

tn表示线程的名字“1-138”表示第1个线程组的第138个线程。

dt表示响应的文件类型

by表示请求和响应的字节数

只要我们把对应的时间替换报告中对应的时间即可

6、优化 把jmeter的实际执行时间匹配进去,最终版本,如下

直接执行命令

 python3 dealReportXml.py result.xml test_demo.py report/resource

allure generate report/resource -o report/html --clean

完整代码如下

# -*- coding: utf-8 -*-

# @Time    : 2020/11/30 4:29 下午

import xml.etree.cElementTreeas ET

import json,os,uuid

import sys

from osimport listdir

from os.pathimport isfile, join

# xmlObject xml工程

# checkString 这个其实是固定值 httpSample,只不过后面想要获取其他结构参数化

# num 当时想嵌套多层,后来发现allure只三层结构,其实这个也没啥用

# result 传递解析的xml

# demoFile 生成的pytes文件

# featureIndex 用来排序参数用例,按照jmeter中的树结果

# storyIndex 同上,是第二层级的排序

# timeChekout 用来替换allure报告中的时间为jmeter报告时间

def checkChildren(xmlObject, checkString, num, result, demoFile, featureIndex, storyIndex,timeChekout):

    for childrenin xmlObject:

        try:

            if num == 1 and children.attrib['sby'] != "0":

                featureIndexStr='#'+str(featureIndex)+" " if featureIndex >= 10 else '#0'+str(featureIndex)+" "

                result["feature"] = featureIndexStr+children.attrib['lb']

                featureIndex += 1

            if num >= 2 and children.tag== "sample":

                storyIndexStr= '#' + str(storyIndex) + " " if storyIndex >= 10 else '#0' + str(

                    storyIndex) + " "

                result["story"] = storyIndexStr+children.attrib['lb']

                storyIndex += 1

        except:

            pass

        if children.tag== checkString:

            result['caseName'] = children.attrib['lb']

            for httpSampleChildrenin children:

                if httpSampleChildren.tag== 'assertionResult':

                    assertionResultChildrenTag=[]

                    for assertionResultChildrenin httpSampleChildren:

                        assertionResultChildrenTag.append(assertionResultChildren.tag)

                        result[assertionResultChildren.tag] = assertionResultChildren.text

if "failureMessage" not in assertionResultChildrenTag:

                        result['failureMessage'] = None

                else:

                    result[httpSampleChildren.tag] = httpSampleChildren.text

feature= result['feature'] if "feature" in result else None

            caseName= result['caseName'] if 'caseName' in result else None

            URL= result['java.net.URL'] if 'java.net.URL' in result else None

            method= result['method'] if 'method' in result else None

            requestHeader= result['requestHeader'] if 'requestHeader' in result else None

            queryString= result['queryString'] if 'queryString' in result else None

            responseData= result['responseData'] if 'responseData' in result else None

            failureMessage= result['failureMessage'] if 'failureMessage' in result else None

            failure= result['failure'] if 'failure' in result else "false"

            menthodUuid= str(uuid.uuid1()).replace('-','')

            start= int(children.attrib['ts'])

            stop= int(children.attrib['ts'])+int(children.attrib['t'])

            timeChekout["test_demo#test_allure_report_"+menthodUuid]={"start":start,"stop":stop}

            storyString= "@allure.story('"+result['story']+"')  # 二级目录" if 'story' in result else ''

            pyString= '''

@allure.feature('{feature}')  # 一级目录{story}

@allure.title("{caseName}")

def test_allure_report_{num}():

    with allure.step('请求url:{URL}'):

        print('请求url:{URL}')

    with allure.step('请求方法:{method}' ):

        print('请求方法:{method}' )

    with allure.step('请求头:{requestHeader}' ):

        print('请求头:{requestHeader}' )

    with allure.step(\'''请求数据:{queryString}\'''):

        print(\'''请求数据:{queryString}\''')

    with allure.step('接口返回:{responseData}'):

        print('接口返回:{responseData}')

    with allure.step('断言结果:{failureMessage}'):

        print('断言结果:{failureMessage}')

    assert "{failure}" == 'false' '''.format(feature=feature,story=storyString,caseName=caseName,

                                            num=menthodUuid,URL=URL,method=method, requestHeader=str(requestHeader).replace('\n', '').replace('\r', ''),

                                            queryString=str(json.dumps(queryString)).replace("'","\""),

                                            responseData=str(json.dumps(responseData)).replace("'","\""),

                                            failureMessage=str(failureMessage).replace("'","\""),failure=failure)

            with open(demoFile,'a') as c:

                c.write(pyString)

        else:

            checkChildren(children,checkString,num+1,result,demoFile,featureIndex,storyIndex,timeChekout)

    return timeChekout

if __name__== '__main__':

    #通过命令行来执行 ,例如python3 dealReportXml.py result.xml test_demo.py report/resource

    commonndLines= sys.argv

with open(commonndLines[2], "w") as demo:

        demo.write('''

# -*- coding: utf-8 -*-

import allure

            ''')

    tree= ET.parse(commonndLines[1])

    root= tree.getroot()

    realQueryTime= checkChildren(root,"httpSample",1,{},commonndLines[2],1,1,{})

    pyString= 'pytest --capture=no '+commonndLines[2]+' --alluredir '+commonndLines[3]

    os.system(pyString)

    files= [mfor min listdir(commonndLines[3]+"/") if isfile(join(commonndLines[3]+"/", m))]

    for filein files:

        if ".json" in file:

            try:

                with open(commonndLines[3]+"/" + file, 'r') as f:

                    jsonStr= json.loads(f.read())

                    start= realQueryTime[jsonStr['fullName']]["start"]

                    stop= realQueryTime[jsonStr['fullName']]["stop"]

                    jsonStr['start'] = start

jsonStr['stop'] = stop

with open(commonndLines[3]+"/" + file, "w") as m:

                        json.dump(jsonStr, m, indent=2, sort_keys=True, ensure_ascii=False)  # 写为多行

            except:

                pass



打开报告看时间和jmeter报告中一样,有没有很爽



你可能感兴趣的:(Jmeter输出报告转allure2)