1. 程式人生 > >python小工具:用python操作HP的Quality Center

python小工具:用python操作HP的Quality Center

over cti 步驟 response headers 服務器 登錄 chm format

背景是這樣的:

這個組的測試人員每跑一個case都要上傳測試結果附件到QC。每個待測功能模塊可能包含幾十上百的case。於是手工上傳測試結果變成了繁重的體力勞動。令人驚訝的是我們的工具開發組竟然說做不了QC的測試結果附件上傳。更讓我驚訝的是,測試人員竟然真的手工上傳結果上傳了大半年了。

以下我寫了個小工具解決這個問題:

思路很簡單,調用hp提供的ALM Rest api接口。把一個個用戶操作轉化成http請求。然後按照接口要求,把附件一個一個上傳到指定的QC test instance上。

主要用的庫是:
requests:負責發送http請求
BeautifulSoup4:負責解析QC服務器返回的響應。
整個工具非常簡單。

具體步驟如下:
先讓用戶登錄進QC

[2017-05-17 13:57:25,023] Starting new HTTP connection (1): XXXXX.com
[2017-05-17 13:57:25,430] post http://XXXXX.com:80/qcbin/authentication-point/authenticate
[2017-05-17 13:57:25,430] headers = {Authorization: Basic XXXXXXX}
[2017-05-17 13:57:25,430] 200 OK
[2017-05-17 13:57:25,430] --------------------

(上面這個帶了時間戳的東西是我的log。每個請求都會自己記下來發了些啥。)

然後按照用戶給定的的test_set_id去QC裏搜索一下這個test set下的test instance有哪些。

[2017-05-17 13:57:25,430] --------------------
[2017-05-17 13:57:26,303] get http://XXXXX.com:80/qcbin/rest/domains/{Domain name}/projects/{Project name}/test-instances?query={contains-test-set.id[XXXXXX]}&fields=id,test-id&page-size=2000
[
2017-05-17 13:57:26,303] 200 OK [2017-05-17 13:57:26,303] --------------------


然後每個test instance id去查一下qc裏對應的test id,也就是測試用例的id,再根據這個id,從qc裏查出測試用例的名字。
搜索的時候,這樣指定返回值的字段名,以下是搜索某個test set id下的test-instance,並且要求返回值只包含test instance id和 test id
test-instances?query={contains-test-set.id[XXX]}&fields=id,test-id&page-size=2000

[2017-05-17 13:57:26,303] --------------------
[2017-05-17 13:57:26,516] get http://XXXXX.com:80/qcbin/rest/domains/XXX/projects/XXX/tests?query={id[XXXXXX]}&fields=name&page-size=2000
[2017-05-17 13:57:26,516] 200 OK
[2017-05-17 13:57:26,516] --------------------


根據上面查出來的test-id再次查詢,得到這個test的name字段值

查出了測試用例的名字是用來和我要上傳的附件做匹配的,這兩個名字對上了,就會把某個附件傳到這個用例對應的test-instance上。

上傳文件部分調用的是這樣的一個requests請求:

data = {
filename: ("", attachment_path+attachment_name),
            override-existing-attachment:("","y")
        }

file = {
file: open(attachment_name, rb)
        }
response = self.session.post(url, files=file,data=data)


最後附上一些代碼,供參考:

這個類是用來做get請求和post請求的。auto_log裝飾器會把發了什麽請求打成log。
不像某些QC操作的庫裏一樣滿屏的打log

import logging as log
import requests


class RestClient:
    def __init__(self):
        self.headers={}
        self.session = requests.Session()
        log.basicConfig(level=log.INFO, format=[%(asctime)s] %(message)s)

    def auto_log(func):
        def wrapper(*args, **kw):
            r = func(*args, **kw)
            log.info("%s %s", func.func_name, args[1])
            for key in kw:
                log.info("%s = %s",key, kw[key])
            log.info("%s %s",r.status_code,r.reason)
            log.info("--------------------")
            return r
        return wrapper

    @auto_log
    def get(self, url):
        return self.session.get(url)

    @auto_log
    def post(self, url, files=None, data=None,headers=None):
        if headers is None:
            headers = self.headers
        return self.session.post(url, headers=headers,files=files,data=data)


第二個類是用來操作QC的,現在我做了用戶登錄、搜索entity、添加附件三個功能。後續還會加上更新entity和創建entity等,把參考文檔裏的common tasks全都實現在這個類裏。

class QCSession:
    def __init__(self, username, password, qc_url):
        self.api_client=RestClient()
        auth = base64.b64encode("{}:{}".format(username, password))
        self.api_client.session.headers[Authorization] = "Basic {}".format(auth)
        self.qc_url = qc_url
        self.login()

    def login(self):
        r = self.api_client.post(self.qc_url.auth, headers=self.api_client.session.headers)
        assert(r.status_code is 200)

    def get(self, *args):
        r = self.api_client.get(self.qc_url.path(*args))
        assert (r.status_code is 200 or r.status_code is 201)
        return r

    def add_attachment(self, filename, over_ride,*args):
        data = {
            filename: ("", filename),
            override-existing-attachment: ("", over_ride)
        }
        files = {
            file: open(filename, rb)
        }
        r = self.api_client.post(self.qc_url.path(*args),data=data,files=files)
        assert (r.status_code is 200 or r.status_code is 201)
        return r

    def query_entitys(self, entity_name, query_expression, fields=None, page_size="2000"):
        """
        :param entity_name: the entity to query 
        :param query_expression: the query expression
        :param fields: the files to return in results
        :param page_size: the result page size, by default is 2000 which is the max value
        :return: resturn the BeautifulSoup parsed result
        """
        query_url=u"%s?query={%s}&fields=%s&page-size=%s" %(entity_name,query_expression,fields,page_size)
        r = self.get(query_url)
        res = BeautifulSoup(r.content, "lxml")
        return res


還有一個保存和生成QC的各種url地址的類:

class QCURL:
    def __init__(self, hostname, domain, project, port=80):
        self.__base = uhttp://{}:{}/qcbin/.format(hostname,port)
        self.__work = self.__base + urest/domains/{}/projects/{}/.format(domain,project)
        self.auth = self.__base + uauthentication-point/authenticate
        self.logout = self.__base + uauthentication-point/logout/

    def path(self, *args):
        return self.__work + /.join([str(arg) for arg in args])


還有第四個類就是用QC Session類來實現我要的業務功能了。具體代碼就不貼了,裏面沒什麽可以讓別人重用的東西。

拿上面三個類就可以用了。
給個例子:
登錄QC,並查詢指定的testset_id下所有的test-instances,並返回其id和test-id
下面所有沒賦值的變量都換成自己環境的真實值的字符串就行了。

qc_url = QCURL(hostname, domain, project, port)
qc_session = QCSession(username, password, qc_url)
qc_session.query_entitys(test-instances, contains-test-set.id[%s] % testset_id, "id,test-id")




希望這篇文章可以幫到一些有同樣問題的人。以上代碼在HP ALM 11.52上測試通過。


參考文檔:

python小工具:用python操作HP的Quality Center