大家好~我是米洛
!
我在从0到1打造一个开源平台, 也在编写一套完整的
接口测试平台系列教程
,希望大家能够多多支持。
回顾
上一节我们讲了适配异步方法
的装饰器,这几节我们继续来死磕用例逻辑
部分。之前已经完善了数据构造器相关的功能,下面我们来进行一系列的改造来支持数据驱动
。
今天就讲一下基础Model。
本节概述
友情提醒: 最近几节会涉及到大量改动,可以直接拉取代码
查看对应的改动。
Github地址: https://github.com/wuranxu/pity
大概的改动部分是,用例的参数不再是单一的,对于同一个场景
进行多组数据的测试。
构思
我们的case目前都是写死的数据,以我们的查询存在用户接口为例子,我们是编写了一个case,然后将name写定在url里面:
如图所示
其实这个name可以有很多组数据,如果只是name在发生变化,得写很多条几乎一样
的case,那可谓是绵羊放了山羊屁。
所以我们可以把数据抽离
出来,有用过ddt的可能都知道,unittest+ddt就可以实现数据驱动
,并且它会为你生成N多个用例。
所以我们的目标就是要和它达成一样的效果。
说了那么多废话,我就是不说怎么做!!!其实,我们维护一个数据表
,里面专门存放测试数据,然后和case通过case_id进行关联,在用例执行的时候取出case的数据不就好了吗?
是的,大概的效果就是这样,但是实现起来还有许多阻碍,后面我们一一道来
。
设计数据表
如果按照以往的尿性,我肯定会设计这样的表:
# 注意这里都是伪代码 class TestCaseData(BaseModel): id = Column(INT) created_at = Column(DATETIME) updated_at = Column(DATETIME) deleted_at = Column(DATETIME) create_user = Column(INT) update_user = Column(INT)
这些都是除了表核心字段以外的不得不添加的基础字段,那每次都写这么多字段,说实话我有点烦
了。
何不定义一个基础的model,然后业务model只保留最核心的字段呢?有了这个想法以后,我就停不下来
了,于是我花了些时间完成这个事情。下面就是实践过程。
设计基础Model
我们知道SqlAlchemy
是拥有BaseModel类的,所有的类模型
都得继承之。
所以我们的基础Model也得继承它。在models目录下建立文件 basic.py
from datetime import datetime from sqlalchemy import INT, DATETIME, Column, BIGINT from app.models import Base class PityBase(Base): id = Column(INT, primary_key=True) created_at = Column(DATETIME, nullable=False) updated_at = Column(DATETIME, nullable=False) deleted_at = Column(BIGINT, nullable=False, default=0) create_user = Column(INT, nullable=False) update_user = Column(INT, nullable=False) def __init__(self, user, id=0): self.created_at = datetime.now() self.updated_at = datetime.now() self.create_user = user self.update_user = user self.id = id
注意因为软删除
的原因,我们把deleted_at改成了BIGINT,而非datetime对象,如果有疑问可看我之前的软删除相关
文章。
这样我们就定义好了PityBase
类。接着我们来说下数据表的设计,其实我们的数据表,你是不确定用户需要多少字段
的。本身我认为这样的数据很适合放到mongo里面,它支持不同类型的数据放到一张表,也可以不定义字段。
但既然我们用的是Mysql
,那我们只能把我们的数据字段写为JSON数据
(字符串),通过序列化/反序列化的方式完成我们的需求。(尽管序列化/反序列影响性能)
测试数据表
""" 测试数据表, 用来存储各个环境下的测试数据,用于数据驱动 """ __author__ = "miluo" from sqlalchemy import Column, INT, String, UniqueConstraint, TEXT from app.models.basic import PityBase class PityTestcaseData(PityBase): env = Column(INT, nullable=False) case_id = Column(INT, nullable=False) name = Column(String(32), nullable=False) json_data = Column(TEXT, nullable=False) __table_args__ = ( UniqueConstraint('env', 'case_id', 'name', 'deleted_at'), ) __tablename__ = "pity_testcase_data" def __init__(self, env, case_id, name, json_data, user, id=0): super().__init__(user, id) self.env = env self.case_id = case_id self.name = name self.json_data = json_data
我们存放了env,case_id,name和json_data这4个字段,并设置了联合唯一索引
,防止数据重复。
可能有的人会好奇,这个name是啥,name
其实是数据的一个标识,也就是个别名而已,用于标识
你的这组数据。
里面的init方法,调用了父类的init(),完成了所有字段的赋值
工作。
这就完事了吗?
其实没有那么简单,我们还需要对PityModel(基础Model)进行一个改动,我们得加一个abstract变量,并设置它为True,这样就能满足我们的要求
了。细心的朋友可以去掉abstract变量试试,你的PityModel会被认为是一个新的数据表,随之会引来报错
。
大家感兴趣可以试试
今天的内容就先说到这里,下一节我们讲TestcaseData的相关操作以及其他变化。以后我们的数据表,如有新增,都会集成自PityModel类,会省不少事儿
。