基于Python Excel的自动化接口测试工具

基于Python Excel的自动化测试工具
搞小工具是一件挺有趣味的一件事情,尤其是还能提高工作效率的时候,这里简要介绍下基于python和excel的自动化接口测试小工具。

流程:

  1. python 解析Excel文件(方便别人使用),读取配置,请求常量 校验规则等。
  2. python 进行case读取,依次调用接口测试。
  3. 输出测试报告文档和统计。

一般而言,对接口测试 的配置项如下:
4. 状态管理:
接口编码 是否使用
5. 接口定义
接口名称 接口描述 接口地址 请求方法 请求头 payload
6. 相应判断
HTTP响应状态码判断 HTTP返回值包含字符串判断 HTTP值相等判断

我们把它做成一个大表。
可放大
值得注意的是:

  1. HTTP状态码包含多值,比如200/201/202
  2. HTTP返回值包含字符串判断 包含多值,比如 包括“1”和“2”
  3. HTTP值相等判断 同样包含多值 比如 vin = 1, din =2 , 左边为变量,右边为值,潜逃变量 写作 a.b.c =1
  4. 支持常量
    先定义两个基本类:
'''
   测试案例POJO
'''
class TestCase:
    def __init__(self, code, name ,description, url,  method, header ,payload, check_rule_set):
        self.code = code
        self.name = name
        self.description = description
        self.url = url
        self.method = method 
        self.header = header
        self.payload = payload 
        self.check_rule_set = check_rule_set

'''
   测试结果
'''
class CheckResult:
    def __init__(self, result, reason):
        self.result = result
        self.reason = reason

开始干活,首先写一个Http 类。

class HttpUtil:

    @classmethod
    def post(cls, url, headers, payload ):
        logging.info("request url: %s, headers: %s, payload: %s", url, headers, payload)
        pre_headers = json.loads(headers)
        post_headers = cls.valid(pre_headers)
        response = requests.post(url, json=json.loads(payload), headers=post_headers)
        logging.info("response: %s, %s", response.status_code, response.json())
        return response
    
    @classmethod
    def get(cls, url, headers):
        logging.info("request url: %s, headers: %s", url, headers)
        pre_headers = json.loads(headers)
        post_headers = cls.valid(pre_headers)
        response = requests.get(url, headers=post_headers)
        logging.info("response: %s, %s", response.status_code, response.json())
        return response
    
    @classmethod
    def put(cls, url, headers, payload ):
        logging.info("request url: %s, headers: %s, payload: %s", url, headers, payload)
        pre_headers = json.loads(headers)
        post_headers = cls.valid(pre_headers)
        response = requests.put(url, json=json.loads(payload), headers=post_headers)
        logging.info("response: %s, %s", response.status_code, response.json())
        return response

接着是Excel操作类:

'''
   Csv操作类
'''
class ExcelUtil:

    max_col = 0
    max_row = 0
    constant_value_set = {}
    case_set = {}   
    input_api_codes = []
    log_dir = "./"
    out_put_file = "./defaul_log.log"

    @classmethod
    def load(cls, file_name):
        '''
            加载配置
        '''
        xl = xlrd.open_workbook(file_name)
        table = xl.sheet_by_name(u"测试用例")
        cls.max_col = table.ncols
        cls.max_row = table.nrows
        log_dir_value = table.cell(1,1).value
        if log_dir_value != None:
            cls.log_dir = log_dir_value
        out_put_file_value = table.cell(2,1).value
        if out_put_file_value != None:
            cls.out_put_file = out_put_file_value

        '''
            加载变量  
        '''
        for i in range(1,cls.max_col):
            if table.cell(6,i).value == 'Y':
                cls.constant_value_set[table.cell(4,i).value] = table.cell(5,i).value
        '''
            加载case  
        '''
        for j in range(9,cls.max_row):
            if table.cell(j,1).value == 'Y':
                cls.input_api_codes.append(table.cell(j,0).value)
                cls.case_set[table.cell(j,0).value] = cls.parse_row_to_case(table.row(j))
        '''
            常量替换
        '''
        for _, case in cls.case_set.items():
            for const_key, const_value in cls.constant_value_set.items():
                const_key_plus = "${" + const_key +"}"
                case.url = case.url.replace(const_key_plus, const_value)
                case.header = case.header.replace(const_key_plus, const_value)
                case.payload = case.payload.replace(const_key_plus, const_value)
                for key, rule in case.check_rule_set.items() :
                    rule = rule.replace(const_key_plus, const_value)
                    case.check_rule_set[key] = rule
            
    @classmethod
    def parse_row_to_case(cls,row_value):
        code = row_value[0].value
        name = row_value[2].value
        description = row_value[3].value
        url = row_value[4].value
        method = row_value[5].value
        header = row_value[6].value
        payload = row_value[7].value
        check_rule_set = {}
        expected_http_code = row_value[8].value
        expected_contains_value = row_value[9].value
        expected_equal_value = row_value[10].value
        if expected_http_code != None and expected_http_code != '':
            check_rule_set[CHECK_HTTPCODE] = str(int(expected_http_code))
        if expected_contains_value != None and expected_contains_value != '':
            check_rule_set[CHECK_VALUE_CONTAINS] = expected_contains_value
        if expected_equal_value != None and expected_equal_value!= '':
            check_rule_set[CHECK_VALUE_EQUAL] = expected_equal_value
        return TestCase(code, name, description, url, method, header, payload, check_rule_set)
    
    @classmethod
    def get_case(cls):
        return cls.case_set

    @classmethod
    def get_input_api_codes(cls):
        return cls.input_api_codes
    
    @classmethod
    def get_output_file(cls):
        return cls.out_put_file

    @classmethod
    def get_log_dir(cls):
        return cls.log_dir

上面都没啥说的,很简单,接着写测试主类和适配各种规则的校验方法:

'''
   测试工具类
'''
class TestTools:

    def __init__(self):
        self.input_case = {}
        self.test_result = {}

    def init(self):
        self.input_case  = ExcelUtil.get_case()
        self.input_api_codes = ExcelUtil.get_input_api_codes()
        self.output_file = ExcelUtil.get_output_file()

    def do_test(self):
        self.init()
        if self.input_api_codes == None:
            logging.error("input_api is None")
            return 
        for api_code in self.input_api_codes:
            if api_code in self.input_case.keys():
                case = self.input_case[api_code]
                try :
                    logging.info("tset api code is: %s", api_code)
                    self.test_item(case)
                except Exception as e:
                    logging.error("exception: %s", e.message)
                    check_result = CheckResult(False, "exception :" + e.message) 
                    self.test_result[case.code] = check_result
            else:
                logging.error("No such case: %s", api_code)
        self.generate_test_result()

    def test_item(self, case):
        if case != None:
            method = case.method
            response = None 
            logging.info("method is :%s", method)
            if method == HTTP_METHOD_GET:
                response = HttpUtil.get(case.url, case.header)
            elif method == HTTP_METHOD_POST:
                response = HttpUtil.post (case.url, case.header, case.payload)
            elif method == HTTP_METHOD_PUT:
                response = HttpUtil.http_get(case.url, case.header, case.payload)
            else:
                pass
            check_result = self.check(response,case.check_rule_set)
        else:
            check_result = CheckResult(False,"case is none")
        self.test_result[case.code] = check_result

    def check(self,response, check_rule_set):
        logging.info("response: %s, check_rule_set keys: %s", response, check_rule_set.keys())
        try:
            if check_rule_set == None:
                return CheckResult(True, "check_rule_set is None" ) 
            if response == None:
                return CheckResult(False, "response is None" ) 
            else:
                for key,value in check_rule_set.items():
                    if key == CHECK_HTTPCODE:
                        if str(response.status_code) != value:
                            return CheckResult(False, " error :CHECK_HTTPCODE, response code is: " + str(response.status_code) + ', expected: '  + str(value))
                        else:
                            logging.info(" pass CHECK_HTTPCODE ")
                    if key == CHECK_VALUE_CONTAINS:
                        if str(response.json()).find(value) == False:
                            return CheckResult(False, "error :CHECK_VALUE_CONTAINS, response not contains: " + value) 
                        else:
                            logging.info(" pass CHECK_VALUE_CONTAINS ")
                    if key == CHECK_VALUE_EQUAL:
                        if SPLIT_MARK not in value:
                            chek_result = self.check_equal(response, value)
                            if chek_result.result == False:
                                return chek_result
                        else:
                            check_equal_items = value.split(SPLIT_MARK)
                            for check_equal_item in check_equal_items:
                                chek_result = self.check_equal(response, check_equal_item)
                                if chek_result.result == False:
                                    return chek_result
                        logging.info(" pass CHECK_VALUE_EQUAL ")
                return CheckResult(True, "all rule set check succeed" ) 

        except Exception as e:
            logging.error("catch exception: %s", e.message)
            check_result = CheckResult(False, "exception :" + e.message)
        logging.info("check result: %s", str(check_result.result)+ "  " +check_result.reason)
        return check_result

        
    def check_equal(self ,response, check_equal_item):
        response_json = response.json()
        check_equal_item_relation = check_equal_item.split(EQUAL_MARK)
        if len(check_equal_item_relation) != 2:
            return CheckResult(False, "invalid rules: "+ check_equal_item) 
        response_value = None
        expected_value = check_equal_item_relation[1]
        try:
            key_list = check_equal_item_relation[0].split(POINT_SPLIT_MARK)
            print key_list
            temp_response_json = response_json
            for key_item in key_list:
                temp_response_json = temp_response_json[key_item]
            response_value = temp_response_json
        except Exception as e:
            logging.error("check_equal_item failed ,rule: %s, error: %s",check_equal_item, e.message)
        if response_value == None:
            return CheckResult(False, "check rules response value is None ,rules: "+ check_equal_item) 
        if str(response_value) == str(expected_value):
            return CheckResult(True, "parse equal check rule: "+ check_equal_item) 
        else:
            return CheckResult(False, "error when equal check rule: "+ check_equal_item + "response value is: " + str(response_value)+ ", expected value is: " + str(expected_value)) 

    def generate_test_result(self):
        count = len(self.test_result)
        success_count = 0
        for _, result_item in self.test_result.items():
            if result_item.result:
                success_count = success_count + 1
        failed_count = count - success_count
        with codecs.open(self.output_file, 'a+', encoding='utf-8') as f:
            f.write('***********************TEST RESSULT**************************\n')
            format_time='%Y-%m-%d_%a_%H-%M-%S'
            time_tup = time.localtime(time.time())
            cur_time = time.strftime(format_time, time_tup)
            time_string = cur_time + '  count: ' + str(count) +  ', success: '  + str(success_count) +', failed: '+  str(failed_count) + '\n'
            f.write(time_string)
            for key ,result in self.test_result.items():
                result_string = key +  "  " + self.input_case[key].name + "   " +  str(result.result) + "  " + result.reason + "\n"
                f.write(result_string)
            f.write('\n\n')

包含上述描述的各校验规则及统计 序列化方法(还不全完善),最后写main方法:

def main():
    file_name = "自动化测试Case.xlsx"
    import sys
    if len(sys.argv) > 1:
        file_name = sys.argv[1]
    ExcelUtil.load(file_name)
    set_log(ExcelUtil.get_log_dir())
    test_tool = TestTools()
    test_tool.do_test()

if __name__ == "__main__":
    main()

大功告成。
日志
测试报告:

TEST RESSULT***
2019-09-05_Thu_19-17-58 count: 2, success: 1, failed: 1
IAM_API_1 根据用户ID获取用户信息 False exception :Value for header {companyid: 2} must be of type str or bytes, not <type ‘int’>
VIN_API_1 车辆信息测试 True all rule set check succeed

TEST RESSULT***
2019-09-05_Thu_19-28-26 count: 2, success: 1, failed: 1
IAM_API_1 根据用户ID获取用户信息 False error when equal check rule: data.iovCurrentVehicle=144115205311821369response value is: 144116206311726088, expected value is: 144115205311821369
VIN_API_1 车辆信息测试 True all rule set check succeed

TEST RESSULT***
2019-09-05_Thu_19-29-44 count: 2, success: 2, failed: 0
IAM_API_1 根据用户ID获取用户信息 True all rule set check succeed
VIN_API_1 车辆信息测试 True all rule set check succeed

还可以,就当随便练练手了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值