zoukankan      html  css  js  c++  java
  • python小工具:用python操作HP的Quality Center

    背景是这样的:

    这个组的测试人员每跑一个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_name),
                'override-existing-attachment':("","y")
            }
    
    file = {
    'file': open(attachmentpath+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 = u'http://{}:{}/qcbin/'.format(hostname,port)
            self.__work = self.__base + u'rest/domains/{}/projects/{}/'.format(domain,project)
            self.auth = self.__base + u'authentication-point/authenticate'
            self.logout = self.__base + u'authentication-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上测试通过。


    参考文档:

  • 相关阅读:
    javaweb基础笔记(2)
    javaweb基础笔记(1)
    java基础笔记(11)
    java基础笔记(10)
    java基础笔记(9)
    洛谷 P2648 赚钱
    AcWing 走廊泼水节 题解
    对于有向图多个点到一个点的求法
    分层图的四倍经验
    洛谷 P4822 [BJWC2012]冻结
  • 原文地址:https://www.cnblogs.com/sdet/p/6874631.html
Copyright © 2011-2022 走看看