专栏首页dongfanger接口自动化框架pyface详细介绍

接口自动化框架pyface详细介绍

版权说明

本框架系本人结合一些实践经验和开源框架设计思想,在家基于兴趣爱好独立完成的代码开发。

源码只保存在私人电脑,办公电脑上无。github开源与公司无关,先把关系撇清,不涉及侵权。

嘘。

框架定位

首先最重要的就是学习交流,无商业用途。其次本框架有一定实用价值,可作为工作辅助工具,解决现有技术无法处理的问题。最后可以优化改造投入生产实用(若有更好的idea请务必告诉我,求知若渴)。

设计思想

技术栈

说明文字为本框架中用途。

python:脚本语言。

requests:http请求库。

allure:测试报告

numpy:数据格式兼容。

pandas:mysql返回数据处理。

PyMySQL:连接mysql。

SQLAlchemy:mysql连接引擎,支持ORM。

texttable:日志打印sql查询结果表格。

目录结构

用例组织方式

模板代码使用code_auto.py自动生成。

        self.api_dir = os.path.join(os.path.join(self.base_dir, 'api'), 'bu')  # 1
        self.case_dir = os.path.join(os.path.join(self.base_dir, 'case'), 'sprint')  # 2
        self.uri = '/api/post'  # 3
        self.description = 'Demo auto code'  # 4
        # 5
        self.body = """{}
"""

1 输入api子目录名称。接口是按业务部门来区分的,子目录名称建议按业务部门(bu==Business Unit)来设置。

2 输入测试用例子目录名称。现在流行敏捷开发,建议按迭代sprint或独立功能模块命名。

3 接口uri。需要注意的是,开头要有1个斜杠/

4 接口描述。如名称、作用。

5 请求体。

执行后在api和case目录生成测试初始化代码。

域名、Headers/Cookie涉及到环境变量,在data/env设置。

class _GldExp:
    x = 1
    headers = {"Content-Type": "application/json"}
    dao_x = Dao('host:port',
                'username',
                'password')

    test_url = 'https://x'


class _Gld:
    x = 2
    headers = {"Content-Type": "application/json"}
    dao_x = Dao('host:port',
                "username",
                "password")

    test_url = 'https://x'


def uuid_list(n):
    """Uuid list

    @param n: Number
    @return: A uuid list
    """
    return [str(uuid.uuid4()).replace('-', '') for i in range(n)]


# Set environment name
vars_ = _GldExp

2个内部类_GldExp_Gld,定义参数化环境变量。

在env文件中可以定义一些业务相关函数。公共函数需要放到common/func,建议不要轻易把框架无关的函数放到公共函数里面。

import env后,使用vars_引用来调用具体的环境变量,如vars_.test_url

测试代码编写方式

api/bu目录下,每个接口==1个py文件。

class ApiPost(Api):

    def __init__(self):
        super().__init__()
        self.url = vars_.test_url + "/api/post"

    def load(self):
        self.body = {}

        return self

    def send(self):
        self.res = self.req.post(url=self.url, headers=vars_.headers, json=self.body)
        self.set_content()
        return self.res

api继承了基类Api。根据不同环境初始化vars_.test_urlload()方法用于加载参数,send()方法用于发送请求(视不同method修改对应的请求方法&参数,如get,可以在common/request.py中找到相关定义)。

测试代码完全面向对象。

def test_default():
    x = ApiPost()
    x.load().send()

这样能很方便的在接口之间传递参数,以及做参数化的工作。

比如,在接口.py中,需要参数化body的name:

    def load(self):
        self.body = {
            "name": self.name
        }

PyCharm会提示此属性未定义,忽略它。

在测试代码中写参数化就很简单:

    x.name = 'dongfanger'
    x.load().send()

JMeter参数化方式

本框架参数化借鉴了JMeter的参数化方式。也就是,在接口发请求后,对参数赋值;在接口收到相应后,提取参数。这也是测试代码要完全面向对象的原因。

面向对象能较好的组织测试代码,使代码逻辑清晰,阅读易于理解。

比如,先定义2个接口,苹果树和商店:

class AppleTree(Api):

    def __init__(self):
        super().__init__()
        self.url = vars_.test_url + "/api/post/apple/tree"

    def load(self):
        self.body = {}

        return self

    def send(self):
        self.res = self.req.post(url=self.url, headers=vars_.headers, json=self.body)
        self.set_content()
        return self.res
class ShopSale(Api):

    def __init__(self):
        super().__init__()
        self.url = vars_.test_url + "/api/post/shop/sale"

    def load(self):
        self.body = {
            "apple": self.apple
        }

        return self

    def send(self):
        self.res = self.req.post(url=self.url, headers=vars_.headers, json=self.body)
        self.set_content()
        return self.res

测试代码编写,苹果树先生产苹果,再运输到商店,商店卖苹果:

def test_apple_to_shop():
    apple_tree = AppleTree()
    apple_tree.load().send()  # 生产苹果
    good_apple = apple_tree.content['good_apple']  # content在Api基类中定义
    shop_sale = ShopSale()
    shop_sale.apple = good_apple  # 传递参数
    shop_sale.load().send()
    print(shop_sale.content)

content在Api基类中定义:

    def set_content(self):
        """After request, assert status and set content

        """
        status_ok(self.res)
        res_json = self.res.json()
        assert 1000 == res_json.get('status')
        try:
            self.content = res_json['content']
        except KeyError:
            logger.info(f"{'*' * 26}\n"
                        f"Response no content\n"
                        f"{'*' * 26}\n")

先断言返回状态ok,再取响应json里面key为content的value。不同公司json规范不一样,需要做调整。

批量执行用例生成测试报告

pytest_allure.py批量执行测试用例。

# Input the directory to run pytest
run_dir = os.path.join(base_dir, 'case')

默认执行case目录下test_开头或结尾的文件(pytest规则)。测试方法需要以test_开头。

可以指定目录,如:

# Input the directory to run pytest
run_dir = os.path.join(os.path.join(base_dir, 'case'), 'sprint0001')

本框架借助pytest_sessionfinish hook函数实现了生成测试报告并自动打开浏览器。

def pytest_sessionfinish(session):
    allure_report_dir_test = session.config.getoption('allure_report_dir')
    if allure_report_dir_test:
        html_dir = os.path.join(allure_report_dir_test, 'html')
        os.system(f'mkdir {html_dir}')
        os.system(f"allure generate {allure_report_dir_test} -o {html_dir}")
        os.system(f"allure open {html_dir}")

mysql支持

mysql主要用于:一提供参数化赋值;二数据库比对断言。

commons/dao.py实现了相关功能。在data/env.py中根据环境定义好连接后,通过vars_使用。

    dao_x = Dao('host:port',
                'username',
                'password')
    sql_result = vars_.dao_x.select('select id, name from new_table;')

dao实现采用了pandas+sqlalchemy,对返回结果取值就可以按dataframe来,如sql_result['name'][0]

借助texttable会打印表格日志,观察数据。

[2020-03-22 18:14:13]Running sql
select id, name from new_table;

[2020-03-22 18:14:14]Sql result:
+----+------+
| id | name |
+====+======+
| 1  | w    |
+----+------+
| 2  | g    |
+----+------+

值得说明的是,为了数据校验方便,默认会把无小数的float转换为int,如5.0->5

    @staticmethod
    def _convert(x):
        """Convert logic code

        @param x: Single cell data
        @return: Converted single cell data
        """
        # float to int
        if isinstance(x, float) and x % 1 == 0:
            return int(x)
        return x

结语

开源使我快乐。

分享才能收获更多。

我在github等你。

https://github.com/dongfanger/pyface 版权申明:本文为博主原创文章,转载请保留原文链接及作者。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 学了元件作用域,我终于对JMeter开窍了

    先看一下这个例子,测试计划“进入考场”下面有一个线程组,线程组下面有 3 个 HTTP 请求,分别是学生登录、考场 token和进入房间:

    测试老树
  • pytest封神之路第六步 断言技巧

    pytest的断言把Python语言简洁的优点发挥的淋漓尽致,因为它用的就是Python的标准断言assert。

    测试老树
  • pytest封神之路第一步 tep介绍

    『 tep is a testing tool to help you write pytest more easily. Try Easy Pytest! ...

    测试老树
  • 第三天:创建型模式--建造者模式

    创建一个由多个部分构成的对象,而且它的构成需要一步接一步地完成,只有当各个部分都创建好后,这个对象才算创建完成。

    喵叔
  • python pyqt5 QToolBar

    import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.Qt...

    用户5760343
  • python:爬取百度贴吧内容

    用户1215343
  • 11 Python 基础: 知识巩固,实现一个简易学生管理系统

    首先,我们定义了一个LoginModule类,此为登录模块,主要功能就是定义账号属性【用户名,密码】,然后定义一个登录login方法实现验证用户名和密码是否正确...

    小Gy
  • [python] 解决OSError:

    用python http.sever实现web服务时,绑定端口由于强制退出导致再次启动服务报错: self.socket.bind(self.server_ad...

    py3study
  • python笔记:随机数,md5,en/decoder

    超级大猪
  • PyQt 5信号与槽的几种高级玩法

    在Qt中,每一个QObject对象和PyQt中所有继承自QWidget的控件(这些都是QObject的子对象)都支持信号与槽机制。当信号发射时,连接的槽函数将会...

    博文视点Broadview

扫码关注云+社区

领取腾讯云代金券