接口自动化框架(Pytest+request+Allure)

前言:

接口自动化是指模拟程序接口层面的自动化,由于接口不易变更,维护成本更小,所以深受各大公司的喜爱。
接口自动化包含2个部分,功能性的接口自动化测试和并发接口自动化测试。
本次文章着重介绍第一种,功能性的接口自动化框架。


一、简单介绍

环境:Mac、Python 3,Pytest,Allure,Request

流程:读取Yaml测试数据-生成测试用例-执行测试用例-生成Allure报告

模块类的设计说明:

Request.py 封装request方法,可以支持多协议扩展(get\post\put)
Config.py 读取配置文件,包括:不同环境的配置,email相关配置
Log.py 封装记录log方法,分为:debug、info、warning、error、critical
Email.py 封装smtplib方法,运行结果发送邮件通知
Assert.py 封装assert方法
run.py 核心代码。定义并执行用例集,生成报告

Yaml测试数据格式如下:

python 复制代码
---
Basic:
  dec: "基础设置"
  parameters:
    -
      url: /settings/basic.json
      data: slug=da1677475c27
      header: {
                 "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko)\
                  Chrome/67.0.3396.99 Safari/537.36",
                 "Content-Type": "keep-alive"
              }

二、代码结构与框架流程

1、代码结构见下图:

2、框架流程见下图:

三、详细功能和使用说明

1、定义配置文件config.ini

该文件中区分测试环境[private_debug]和正式环境[online_release]分别定义相关配置项,[mail]部分为邮件相关配置项

python 复制代码
# http接口测试框架配置信息

[private_debug]
# debug测试服务
tester = your name
environment = debug
versionCode = your version
host = www.jianshu.com
loginHost = /Login
loginInfo = email=wang@user.com&password=123456

[online_release]
# release正式服务
tester = your name
environment = release
versionCode = v1.0
host = www.jianshu.com
loginHost = /Login
loginInfo = email=wang@user.com&password=123456

[mail]
#发送邮件信息
smtpserver = smtp.163.com
sender = test1@163.com
receiver = wang@user.com
username = wang@user.com
password = 123456

2、读取yaml测试数据后封装

yaml测试数据例子见第一节,一条接口可定义多条case数据,get_parameter为已封装好的读取yaml数据方法,循环读取后将多条case数据存在list中。

python 复制代码
class Basic:
    params = get_parameter('Basic')
    url = []
    data = []
    header = []
    for i in range(0, len(params)):
        url.append(params[i]['url'])
        data.append(params[i]['data'])
        header.append(params[i]['header'])

3、编写用例

python 复制代码
class TestBasic:
    @pytest.allure.feature('Home')
    @allure.severity('blocker')
    @allure.story('Basic')
    def test_basic_01(self, action):
        """
            用例描述:未登陆状态下查看基础设置
        """
        conf = Config()
        data = Basic()
        test = Assert.Assertions()
        request = Request.Request(action)

        host = conf.host_debug
        req_url = 'http://' + host
        urls = data.url
        params = data.data
        headers = data.header

        api_url = req_url + urls[0]
        response = request.get_request(api_url, params[0], headers[0])

        assert test.assert_code(response['code'], 401)
        assert test.assert_body(response['body'], 'error', u'继续操作前请注册或者登录.')
        assert test.assert_time(response['time_consuming'], 400)
        Consts.RESULT_LIST.append('True')

4、运行整个框架run.py

python 复制代码
if __name__ == '__main__':
    # 定义测试集
    allure_list = '--allure_features=Home,Personal'
    args = ['-s', '-q', '--alluredir', xml_report_path, allure_list]
    log.info('执行用例集为:%s' % allure_list)
    self_args = sys.argv[1:]
    pytest.main(args)
    cmd = 'allure generate %s -o %s' % (xml_report_path, html_report_path)

    try:
        shell.invoke(cmd)
    except:
        log.error('执行用例失败,请检查环境配置')
        raise

    try:
        mail = Email.SendMail()
        mail.sendMail()
    except:
        log.error('发送邮件失败,请检查邮件配置')
        raise

5、err.log实例

python 复制代码
[ERROR 2018-08-24 09:55:37]Response body != expected_msg, expected_msg is {"error":"继续操作前请注册或者登录9."}, body is {"error":"继续操作前请注册或者登录."}
[ERROR 2018-08-24 10:00:11]Response time > expected_time, expected_time is 400, time is 482.745
[ERROR 2018-08-25 21:49:41]statusCode error, expected_code is 208, statusCode is 200

6、Assert部分代码

python 复制代码
def assert_body(self, body, body_msg, expected_msg):
        """
        验证response body中任意属性的值
        :param body:
        :param body_msg:
        :param expected_msg:
        :return:
        """
        try:
            msg = body[body_msg]
            assert msg == expected_msg
            return True

        except:
            self.log.error("Response body msg != expected_msg, expected_msg is %s, body_msg is %s" % (expected_msg, body_msg))
            Consts.RESULT_LIST.append('fail')

            raise

    def assert_in_text(self, body, expected_msg):
        """
        验证response body中是否包含预期字符串
        :param body:
        :param expected_msg:
        :return:
        """
        try:
            text = json.dumps(body, ensure_ascii=False)
            # print(text)
            assert expected_msg in text
            return True

        except:
            self.log.error("Response body Does not contain expected_msg, expected_msg is %s" % expected_msg)
            Consts.RESULT_LIST.append('fail')

            raise

7、Request部分代码

python 复制代码
def post_request(self, url, data, header):
        """
        Post请求
        :param url:
        :param data:
        :param header:
        :return:

        """
        if not url.startswith('http://'):
            url = '%s%s' % ('http://', url)
            print(url)
        try:
            if data is None:
                response = self.get_session.post(url=url, headers=header)
            else:
                response = self.get_session.post(url=url, params=data, headers=header)

        except requests.RequestException as e:
            print('%s%s' % ('RequestException url: ', url))
            print(e)
            return ()

        except Exception as e:
            print('%s%s' % ('Exception url: ', url))
            print(e)
            return ()

        # time_consuming为响应时间,单位为毫秒
        time_consuming = response.elapsed.microseconds/1000
        # time_total为响应时间,单位为秒
        time_total = response.elapsed.total_seconds()

        Common.Consts.STRESS_LIST.append(time_consuming)

        response_dicts = dict()
        response_dicts['code'] = response.status_code
        try:
            response_dicts['body'] = response.json()
        except Exception as e:
            print(e)
            response_dicts['body'] = ''

        response_dicts['text'] = response.text
        response_dicts['time_consuming'] = time_consuming
        response_dicts['time_total'] = time_total

        return response_dicts

四、Allure报告及Email

1、Allure报告总览,见下图:

2、Email见下图:


五、后续优化

1、集成Jenkins,使用Jenkins插件生成Allure报告

2、多线程并发接口自动化测试

3、接口加密,参数加密


【下面是我整理的2023年最全的软件测试工程师学习知识架构体系图】


一、Python编程入门到精通

二、接口自动化项目实战

三、Web自动化项目实战

四、App自动化项目实战

五、一线大厂简历

六、测试开发DevOps体系

七、常用自动化测试工具

八、JMeter性能测试

九、总结(尾部小惊喜)

生命不息,奋斗不止。每一份努力都不会被辜负,只要坚持不懈,终究会有回报。珍惜时间,追求梦想。不忘初心,砥砺前行。你的未来,由你掌握!

生命短暂,时间宝贵,我们无法预知未来会发生什么,但我们可以掌握当下。珍惜每一天,努力奋斗,让自己变得更加强大和优秀。坚定信念,执着追求,成功终将属于你!

只有不断地挑战自己,才能不断地超越自己。坚持追求梦想,勇敢前行,你就会发现奋斗的过程是如此美好而值得。相信自己,你一定可以做到!

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

相关推荐
fruge2 小时前
前端自动化脚本:用 Node.js 写批量处理工具(图片压缩、文件重命名)
前端·node.js·自动化
Logan Lie2 小时前
Web服务监听地址的取舍:0.0.0.0 vs 127.0.0.1
运维·后端
Y淑滢潇潇2 小时前
RHCE 防火墙实验
linux·运维·rhce
稻谷君W3 小时前
Ubuntu 远程访问 Win11 WSL2 并固定访问教程
linux·运维·ubuntu
泡沫·3 小时前
4.iSCSI 服务器
运维·服务器·数据库
20岁30年经验的码农3 小时前
Java JVM 技术详解
java·jvm·压力测试
悠悠121384 小时前
告别Zabbix?我用Netdata只花10分钟就搞定了50台服务器的秒级监控(保姆级实战)
运维·服务器·zabbix
天庭鸡腿哥4 小时前
大小只有4K的软件,可让系统瞬间丝滑!
运维·服务器·windows·microsoft·everything
虚伪的空想家4 小时前
华为昇腾Atlas 800 A2物理服务器开启VT-d模式
运维·服务器·ubuntu·kvm·vt-d·直通
学渣676564 小时前
服务器端口映射
运维·服务器