使用 python 的 HP ALM 结果附件和状态更新

Posted

技术标签:

【中文标题】使用 python 的 HP ALM 结果附件和状态更新【英文标题】:HP ALM results attachment and status update using python 【发布时间】:2020-04-11 01:45:24 【问题描述】:

挑战:将屏幕截图附加到 TestLab 中的测试,将状态更新为 PASS/FAIL 步骤明智(当前更新通过状态就足够了)

我希望在 python 中编写一个脚本,将测试结果附加到测试实验室中存在的测试用例,然后将每个测试步骤的预期结果设置为“如预期”并逐步通过 TC。

即在手动执行时,我们选择案例,单击运行,然后在预期输出区域中输入“按预期”并通过该步骤,然后对测试用例上的所有测试步骤执行此操作。这需要自动化。我有一个包含截图的文件夹(类似于 TC 名称),所以脚本应该上传截图并更新状态。

到目前为止我已经尝试过什么:

我能够连接到 alm ,使用部分测试用例名称,我能够从测试计划中提取完整的测试用例名称,但不幸的是我仍在努力实现最终目标。

到目前为止我的代码:

import win32com
from win32com.client import Dispatch
import codecs
import re
import json

# Login Credentials
qcServer = "https://almurl.saas.microfocus.com/qcbin/"
qcUser = "my_username"
qcPassword = "pwd"
qcDomain = "domain"
testList = []

testdict = 
project = "Crew_Management"
  # Do the actual login
td = win32com.client.Dispatch("TDApiOle80.TDConnection.1")
td.InitConnectionEx(qcServer)
td.Login(qcUser,qcPassword)
td.Connect(qcDomain,project)
if td.Connected == True:
    print ("System: Logged in to " +project)
else:
    print ("Connect failed to " +project)

mg = td.TreeManager  # Tree manager
name = ['TC001','TC002','TC003','TC003','TC004','TC005','TC006','TC007','TC008','TC009','TC010','TC011','TC012','TC013','TC014']
folder = mg.NodeByPath('Subject\\Test Factory\\MPG\\MPG Regression Test_Yearly Request\\GUI')
for x in name:
    testList = folder.FindTests(x)
    #print(type(testList))
    print(testList[0].Name)
    print(testList[0].DesStepsNum)

td.Disconnect()
td.Logout()

非常感谢任何帮助或指导!

【问题讨论】:

你要找的都在这里github.com/macroking/ALM-Integration/blob/master/… 是否有任何文档或教程可以理解这一点?我推断,我可以从常用框架的输出 xml 文件中执行上述操作。我不太确定如何修改它,出于我的目的,文档或教程会很棒。我知道要求太多了..但我被困住了 【参考方案1】:

假设您有 Python 方面的工作经验。在这里,我正在编写完成您的任务所需的所有不同功能。

参考:https://admhelp.microfocus.com/alm/api_refs/REST_TECH_PREVIEW/ALM_REST_API_TP.html

全局变量

import re
import json
import datetime
import time
import sys
import os, fnmatch
from os import listdir
from os.path import isfile, join
from xml.etree.ElementTree import Element, SubElement, tostring, parse
import glob
from requests.auth import HTTPBasicAuth
import requests

ALM_USER_NAME = ""
ALM_PASSWORD = ""
ALM_DOMAIN = ""
ALM_URL = ""
AUTH_END_POINT = ALM_URL + "authentication-point/authenticate"
QC_SESSION_END_POINT = ALM_URL + "rest/site-session"
QC_LOGOUT_END_POINT = ALM_URL + "authentication-point/logout"
ALM_MIDPOINT = "rest/domains/" + ALM_DOMAIN + "/projects/"
PATH_SEP = os.path.sep

登录功能

    def alm_login(self):
        """
            Function    :   alm_login
            Description :   Authenticate user
            Parameters  :   global parameter
                            alm_username     -   ALM User
                            alm_password     -   ALM Password
        """
        response = self.alm_session.post(AUTH_END_POINT,
                                         auth=HTTPBasicAuth(ALM_USER_NAME, ALM_PASSWORD))
        if response.status_code == 200:
            response = self.alm_session.post(QC_SESSION_END_POINT)
            if response.status_code == 200 | response.status_code == 201:
                print "ALM Authentication successful"
            else:
                print "Error: ", response.staus_code
        else:
            print "Error: ", response.staus_code
        self.alm_session.headers.update('Accept':'application/json',
                                         'Content-Type': 'application/xml')
        return

退出功能

注销方法成功后cookie应该过期

    def alm_logout(self):
        '''
            Function    :   alm_logout
            Description :   terminate user session
            Parameters  :   No Parameters
        '''
        response = self.alm_session.post(QC_LOGOUT_END_POINT)
        print "Logout successful", response.headers.get('Expires'), response.status_code
        return

获取测试集文件夹

如果测试用例跨越多个测试套件,那么最好先获取测试集文件夹并找到必要的测试套件。

    def find_test_set_folder(self):
        '''
            Function    :   find_test_set_folder
            Description :   This sends a couple of http request and authenticate the user
            Parameters  :   1 Parameter
                            test_set_path    -   ALM test set path
        '''
        json_str = json.loads(self.find_folder_id(self.test_set_path.split("\\"), "test-set-folders"
                                                  , 0, "id"))
        if 'entities' in json_str:
            return create_key_value(json_str['entities'][0]['Fields'])['id']
        else:
            return create_key_value(json_str['Fields'])['id']

获取文件夹 ID

此方法将帮助您找到测试套件文件夹 ID 或测试计划文件夹 ID。

    def find_folder_id(self, arrfolder, str_api, parent_id, fields):
        '''
            Function    :   find_folder_id
            Description :   This sends a couple of http request and authenticate the user
            Parameters  :   1 Parameter
                            test_set_path    -   ALM test set path
        '''
        for foldername in arrfolder:
            payload = "query": "name['" + foldername + "'];parent-id[" + str(parent_id) + "]",
                       "fields": fields
            response = self.alm_session.get(ALM_URL + ALM_MIDPOINT + "/" + str_api, params=payload)
            obj = json.loads(response.text)
            if obj["TotalResults"] >= 1:
                parent_id = get_field_value(obj['entities'][0]['Fields'], "id")
                # print("folder id of " + foldername + " is " + str(parent_id))
            else:
                # print("Folder " + foldername + " does not exists")
                inputdata = dict()
                inputdata['Type'] = str_api[0:len(str_api) - 1]
                inputdata['name'] = foldername
                inputdata['parent-id'] = str(parent_id)
                data = generate_xml_data(inputdata)
                response = self.alm_session.post(ALM_URL + ALM_MIDPOINT + "/" + str_api, data=data)
                obj = json.loads(response.text)
                if response.status_code == 200 | response.status_code == 201:
                    parent_id = get_field_value(obj['Fields'], "id")
                    # print("folder id of " + foldername + " is " + str(parent_id))
        return response.text

创建运行实例

在更新测试状态之前,我们必须为测试创建一个运行实例。

def create_run_instance(self, test_set_id, test_map):
        '''
            Function    :   create_run_instance
            Description :   Create new run instances
            Parameters  :   Test Set Id
        '''
        str_api = "test-instances"
        fields = "id,test-id,test-config-id,cycle-id"
        payload = "query": "cycle-id['" + test_set_id + "']", "fields": fields,
                   "page-size": 5000
        response = self.alm_session.get(ALM_URL + ALM_MIDPOINT + "/" + str_api, params=payload)
        obj = json.loads(response.text)

        run_instance_post = "<Entities>"
        for entity in obj["entities"]:
            run_name = re.sub('[-:]', '_',
                              'automation_' + datetime.datetime.fromtimestamp(time.time()).strftime(
                                  '%Y-%m-%d %H:%M:%S'))
            temp_map = create_key_value(entity["Fields"])
            _test_id = int(temp_map['test-id'])
            self.parser_temp_dic[_test_id]['testcycl-id'] = temp_map['id']
            self.parser_temp_dic[_test_id]['test-config-id'] = temp_map['test-config-id']
            self.parser_temp_dic[_test_id]['test-id'] = temp_map['test-id']
            self.parser_temp_dic[_test_id]['cycle-id'] = temp_map['cycle-id']
            # parser_temp_dic[int(temp_map['test-id'])]['status'].sort()
            status = "Passed"
            if 'Failed' in self.parser_temp_dic[int(temp_map['test-id'])]['status']:
                status = 'Failed'
            self.parser_temp_dic[int(temp_map['test-id'])]['final-status'] = status

            inputdata = dict()
            inputdata['Type'] = 'run'
            inputdata['name'] = run_name
            inputdata['owner'] = ALM_USER_NAME
            inputdata['test-instance'] = str(1)
            inputdata['testcycl-id'] = str(temp_map['id'])
            inputdata['cycle-id'] = str(temp_map['cycle-id'])
            inputdata['status'] = 'Not Completed'
            inputdata['test-id'] = temp_map['test-id']
            inputdata['subtype-id'] = 'hp.qc.run.MANUAL'
            data = generate_xml_data(inputdata)
            run_instance_post = run_instance_post + data

        self.bulk_operation("runs", run_instance_post + "</Entities>", True, "POST")
        return

更新运行实例

    def update_run_instance(self, test_set_id):
        '''
            Function    :   update_run_instance
            Description :   Update the test status in run instances
            Parameters  :   No input parameter
        '''
        fields = "id,test-id"
        payload = "query": "cycle-id['" + test_set_id + "']", "fields": fields,
                   "page-size": 5000
        response = self.alm_session.get(ALM_URL + ALM_MIDPOINT + "/runs", params=payload)
        obj = json.loads(response.text)

        run_instance_put = "<Entities>"
        for entity in obj["entities"]:
            if len(entity["Fields"]) != 1:
                temp_map = create_key_value(entity["Fields"])
                self.parser_temp_dic[int(temp_map['test-id'])]['run-id'] = temp_map['id']
                inputdata = dict()
                inputdata['Type'] = 'run'
                inputdata['id'] = str(temp_map['id'])
                intermediate_ = self.parser_temp_dic[int(temp_map['test-id'])]['testcycl-id']
                inputdata['testcycl-id'] = str(intermediate_)
                inputdata['status'] = self.parser_temp_dic[int(temp_map['test-id'])]['final-status']
                data = generate_xml_data(inputdata)
                run_instance_put = run_instance_put + data

        self.bulk_operation("runs", run_instance_put + "</Entities>", True, "PUT")
        return

上传结果文件

将文件上传到 ALM 中的任何对象

    def upload_result_file(self, test_set_id, report_file):
        '''
            Function    :   upload_result_file
            Description :   Upload test result to ALM
        '''
        payload = open(report_file, 'rb')
        headers = 
        headers['Content-Type'] = "application/octet-stream"
        headers['slug'] = "test-results" + report_file[report_file.rfind(".")+1: ]
        response = self.alm_session.post(ALM_URL + ALM_MIDPOINT + "/test-sets/" +
                                         str(test_set_id) + "/attachments/",
                                         headers=headers, data=payload)
        if not (response.status_code == 200 or response.status_code == 201):
            print "Attachment step failed!", response.text, response.url, response.status_code
        return

批量操作

这是一个帮助我们发布数据数组的助手。

    def bulk_operation(self, str_api, data, isbulk, request_type):
        '''
            Function    :   Post Test Case / Test Instance
            Description :   Generic function to post multiple entities.
            Parameters  :   3 parameters
                            str_api          -   End point name
                            data             -   Actual data to post
                            isbulk           -   True or False
        '''
        response = None
        headers = 
        try:
            if isbulk:
                headers['Content-Type'] = "application/xml;type = collection"
            if request_type == 'POST':
                response = self.alm_session.post(ALM_URL + ALM_MIDPOINT + "/" + str_api, data=data,
                                                 headers=headers)
            elif request_type == 'PUT':
                response = self.alm_session.put(ALM_URL + ALM_MIDPOINT + "/" + str_api, data=data,
                                                headers=headers)
        except Exception as err:
            print err
        if response.status_code == 200 | response.status_code == 201:
            return response.text
        return response

【讨论】:

我有一个关于附件文件大小的问题。我尝试上传一个 2mb 的文件失败了,显示错误。有没有办法上传大文件? 大小限制由 ALM 管理员管理,请与您的 ALM 管理员进行对话。在了解了你的用例之后,他应该能够提高限制。【参考方案2】:

您可以参考此代码 https://github.com/arunprabusamy/Python-Libraries/blob/main/alm_RestAPI/almLib.py

您只需发送三个值 - 测试集 ID(周期 ID)、ALM 测试 ID 和执行状态。该库自动构建 json 有效负载并创建测试运行和更新结果。

【讨论】:

以上是关于使用 python 的 HP ALM 结果附件和状态更新的主要内容,如果未能解决你的问题,请参考以下文章

能否在 HP ALM 中跟踪 TestCafe 结果?

Selenium 与 HP ALM 的集成

HP ALM

如何在 HP ALM 中更新测试运行的环境值

HP LoadRunner:怎样连接到HP ALM的CAC模式?

HP ALM lis