接口框架辅助类的深度解析(下篇)

44 阅读6分钟

接口配置源码揭秘

在本次接口框架实战项目中的示例文件为configHttp.py,放在commomsrc文件夹内。接下来我们来分析一下文件内容。 这部分的代码主要使用的是requests库,对requests库的一些请求形式进行封装。后续脚本编写以及请求参数传递都需要用到这个库的封装。代码主要做的是基本参数配置、请求参数设置、get请求、post请求。 首先头部依然是导入一些需要的库和文件,接下来对配置文件读取方法做初始化的操作。

import requests
import readConfig as readConfig
from commonsrc.Log import MyLog as Log
from commonsrc.login import testlogin
import requests,json


localReadConfig = readConfig.ReadConfig()
s = testlogin().test_login()

基本参数配置,这里配置了整个ConfigHttp类的全局变量和私有变量,全局变量的值从配置文件ini里获取,私有变量先默认为空,后续脚本编写时在传入值。

class ConfigHttp:

    def __init__(self):
        global scheme, host, port, timeout
        scheme = localReadConfig.get_http("scheme")
        port = localReadConfig.get_http("port")
        timeout = localReadConfig.get_http("timeout")
        self.log = Log.get_log()
        self.logger = self.log.get_logger()
        self.headers = {}
        self.params = {}
        self.data = {}
        self.url = None
        self.files = {}
        self.state = 0
        #self.cookies = get_login_cookies()
        #localConfigHttp.set_cookies(self.cookies)

请求参数设置,请求参数主要有请求的头,向什么链接请求,请求内容是什么。下面这个函数set_url就是请求链接的获取,传参url即可组成一个完整的接口。请求头set_headers是外部脚本获取到的;set_params、set_data也都是从外部进行获取值的,这里为什么设置两个函数是因为post和get的请求方法的一个差异。Set_files是用于给接口一个文件,就是上传文件这么个功能。

    def set_url(self, host,url):
        """
        set url
        :param: interface url
        :return:
        """
        #self.url = scheme+'://'+host+url
        self.url = host+url
        return self.url
    def set_cookies(self,cookies):
        """

        :return:
        """
        self.cookies=cookies

    def set_headers(self, header):
        """
        set headers
        :param header:
        :return:
        """
        self.headers = header


    def set_params(self, param):
        """
        set params
        :param param:
        :return:
        """
        self.params = param


    def set_data(self, data):
        """
        set data
        :param data:
        :return:
        """
        self.data = data

    def set_files(self, filename):
        """
        set upload files
        :param filename:
        :return:
        """
        if filename != '':
            file_path = 'F:/AppTest/Test/interfaceTest/testFile/img/' + filename
            self.files = {'file': open(file_path, 'rb')}

        if filename == '' or filename is None:
            self.state = 1

http的请求方式有GET和POST两种,get通常从服务器中获取数据,而post是提交数据给指定的服务器。两个函数都返回了接口数据,以备后续脚本验证所用。

# defined http get method
    def get(self):
        """
        defined get method
        :return:
        """
        requests.packages.urllib3.disable_warnings()
        try:
            return_data = s.get(self.url, headers=self.headers, params=self.params, timeout=float(timeout))
            # response.raise_for_status()
            return return_data
        except TimeoutError:
            self.logger.error("Time out!")
            return None

    # defined http post method
    # include get params and post data
    # uninclude upload file
    def post(self):
        """
        defined post method
        :return:
        """
        requests.packages.urllib3.disable_warnings()
        try:

            return_data = s.post(self.url, headers=self.headers,  data=self.data, verify=False,timeout=float(timeout))
            # response.raise_for_status()
            print(return_data.text)
            #info = return_data.json()

            return return_data

        except TimeoutError:
            self.logger.error("Time out!")
            return None

这里是post的另一个需求而已上传文件到接口的需求,基本源码一样。

# defined http post method
    # include upload file
    def postWithFile(self):
        """
        defined post method
        :return:
        """
        requests.packages.urllib3.disable_warnings()
        try:
            response = s.post(self.url, headers=self.headers, data=self.data, files=self.files, timeout=float(timeout))
            return response
        except TimeoutError:
            self.logger.error("Time out!")
            return None

请求参数为json的一个调用。

 # defined http post method
    # for json
    def postWithJson(self):
        """
        defined post method
        :return:
        """
        requests.packages.urllib3.disable_warnings()
        try:
            response =s.post(self.url, headers=self.headers, json=self.data, timeout=float(timeout))
            return response
        except TimeoutError:
            self.logger.error("Time out!")
            return None

接口状态保持策略揭秘

在我们真正投入到实际工作中后会遇到这么一种接口,这些接口都是开发给第三方的,这种接口是不需要登录验证的只要请求参数能验证通过即可。这种对外接口的测试会相对简单。

但是在做自有接口自动化测试时,我们经常会遇到一个一致性的问题,那么就是如何保持用户一直在登录状态,只有在登录状态时有些接口发送请求才能获取正确的json返回,或者说大部分的接口正确返回结果的前提是在用户已经校验和验证的前提下的。获取大家会想到用token呀、用cookie呀、还有每次请求登录一次呀,又或者长久保持seesion呀。其实这些方法都可以只是选择哪种最为方便,最为合适的问题,选择完方法以后如何在代码里实现又是另一种考量了。 本项目在做接口登录状态时,用了很多种方法,最后经过比较感觉还是使用cookie、token的方法较为合适。具体是使用token,还是cookie或者两者都使用,这个要看项目的需求和实际情况。 首先来看第一种方法token的方法,在ini文件中我们去保存上一次的接口返回的token。 保存方法的源码我们放在common里。登录验证这里我们要把post方法里的verify置为false,这样登录才能成功,获取token才顺利。这段代码保证了token的值是最新的。

第二种方法cookies的方法,这里没没去加判断,正常是要有一个判断的,主要的代码基本一样

# login
def get_login_cookies():
    host = localReadConfig.get_http("url")
    headers = {"Host": "www.mujin.assignee.com",
               "Connection": "keep-alive",
               "Content-Length": "2",
               "Accept": "application/json, text/plain, */*",
               "Origin": "https://www.mujin.assignee.com"

               }
    data = {"username":1222,"password":"Aa123456","jCaptchaCode":"","holder":"SPONSOR"

    }

    response = requests.post(host + "/api/login", data=data, headers=headers,
                             verify=False)
    info = response.json()
    cookie=response.cookies.get_dict()
    print("登录状态:",info["msg"])

    return response.cookies

那么来看一下最终在ini文件了保存的值是这样的。

通常情况下我们都是通过token和cookies来保持登录状态的,但是实际项目中总有不尽人意的地方如接口提交后没有返回token或者cookies,又或者返回的token和cookies保持的失效性很短。那么又该如何做接口测试呢? 在request模块里有一个方法Session(),我们通过定义一个全局的session来保持整个测试的登录状态,在接口用例参数化的脚本中直接调用次方法即可进行测试。定义全局session的代码如下:

import requests

'''在登陆模块创建一个全局session,在其他接口操作时带入登陆时的session,保持session的一致性'''
s = requests.Session()#定义一个全局session
class testlogin():
    def __init__(self):
        self.login_url = "https://www.zhiling.robotsh.com/api/login"
        self.username = "test03"
        self.password = "Aa123456"
    def test_login(self):
        da={
            "userAccount":self.username,
            "password":self.password}
        response = s.post(self.login_url,json=da,verify=False)
        info = response.json()
        print(info)
        print('login_sucsse')
        return s
if __name__ == '__main__':
    a=testlogin()
    a.test_login()

同时在接口配置源码里configHttp.py文件中加入调用即可,源码如下:

至此就基本可以应对全部的接口测试登录状态保持需求了。

文章原创首发于微信公众号 软件测试微课堂,更多内容欢迎关注微信公众号查看