大家好~我是
米洛
!
我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的教程
,希望大家多多支持。
欢迎关注我的公众号米洛的测开日记
,一起交流学习!
# 回顾
上一节我们稍微优化了一下登录页,后面我们可以开始进一步开发了,以功能点为主。所以这一节我们要解决这样一个需求:
其实这个问题是因为http
请求发出去的时候,并没有进行全局变量
替换,但现在有个很严重的问题:
我们的case都是跨环境的,这就导致如果这里填了环境变量,但我并不知道该用哪套环境的数据,而且这里也漏了我们之前编写的base_path功能。
# 改造方案
这次的方案改动会很大,我个人觉得,新增和编辑页面完全区分开,比较不合适。而且不太友好,所以在添加case的时候,我会以弹窗的形式展示。
这样能够少跳转一次url,相对来说
更友好一些。至于那么多操作条件,咱们就一并提交。
用例信息
前置条件
后置条件
断言
组件我们是不能复用了,因为之前添加前置/后置/断言,都是在已有的用例上添加,现在都是
暂存
到前端,最后统一提交,没事我们慢慢来,迟早要走到这一步的。
# 编写后端代码
后端代码,我们需要做的有2部分:
- 批量提交用例数据
- 根据传入的数据在线执行case(供调试用,这点比较麻烦)
那我们就先从软柿子开捏吧,因为第二个部分可能还有些问题,我们可以放到后面去做。
首先我们要综合来看,新增是全部数据一并提交,而修改往往是只修改一部分,其实修改我们也可以改为批量提交
,但是代价很大,因为要改的内容多,还是抽出比较合适。这样就会有一个问题了,我们的前置条件等表单,都是需要case_id
字段的,所以这里我们为了新的模式,只能把它改成非必填了。(这点我还没有考虑好,只是初步的设定)
- 修改各个表的form
这里前后置条件本身就忘记
加上这个约束了,所以也不太需要改,重点都是validator这个方法里面。
- 编写大杂烩form 暂且叫TestCaseInfo
它结合了4种schema,我测试了发现,会根据里面的schema进行校验,所以我们的validator只需要校验case字段即可。
改写insert_record方法
在此之前,我们需要先改造下Mapper里面的insert_record方法,由于我们是批量插入,所以需要用一个事务去
保证
所有数据要么都插入要么都失败,之前我的设想是在router层创建session,并开启事务,接着把session投递到对应的插入操作中,所以我们需要改改insert方法:
如果ss(代表session)传入了,说明是一个事务操作,其实也可以改个名字叫transaction,但是因为我们还是需要拿到session信息的,所以暂时先这么写了。除了参数多了个ss以外,没有其他区别了。
编写insert_test_case方法
在TestCaseDao类编写insert_test_case方法,主要有3步:
- 判断该目录是否存在该case名
- 添加case
- 添加断言/前后置条件/测试数据
@staticmethod
async def insert_test_case(session, data: TestCaseInfo, user: int):
"""
测试数据和用户id
:param data: 测试用例数据
:param session: 异步session
:param user: 创建人
:return:
"""
query = await session.execute(
select(TestCase).where(TestCase.directory_id == data.case.directory_id, TestCase.name == data.case.name,
TestCase.deleted_at == 0))
if query.scalars().first() is not None:
raise Exception("用例名称已存在")
cs = TestCase(**data.case.dict(), create_user=user)
# 添加case,之后添加其他数据
session.add(cs)
await session.flush()
session.expunge(cs)
# # 添加断言
for a in data.asserts:
a.case_id = cs.id
a = TestCaseAsserts(**a.dict(), user=user)
await TestCaseAssertsDao.insert_record(a, ss=session)
# 添加构造条件
for c in data.constructor:
c.case_id = cs.id
c = Constructor(**c.dict(), user=user)
await ConstructorDao.insert_record(c, ss=session)
# 添加测试数据
for t in data.data:
t.case_id = cs.id
t = PityTestcaseData(**t.dict(), user=user)
await PityTestcaseDataDao.insert_record(t, ss=session)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
思路比较简单,但是有没有觉得代码很冗余
,差不多的步骤写了3遍。所以这时候我们就可以把重复的代码剥离出来,组成一个新的方法,来看看:
@staticmethod
async def _insert(session, case_id: int, user: int, form: TestCaseInfo, **fields: tuple):
for field, model_info in fields.items():
md, model = model_info
field_data = getattr(form, field)
for f in field_data:
setattr(f, "case_id", case_id)
data = model(**f.dict(), user=user)
await md.insert_record(data, ss=session)
@staticmethod
async def insert_test_case(session, data: TestCaseInfo, user: int):
"""
测试数据和用户id
:param data: 测试用例数据
:param session: 异步session
:param user: 创建人
:return:
"""
query = await session.execute(
select(TestCase).where(TestCase.directory_id == data.case.directory_id, TestCase.name == data.case.name,
TestCase.deleted_at == 0))
if query.scalars().first() is not None:
raise Exception("用例名称已存在")
cs = TestCase(**data.case.dict(), create_user=user)
# 添加case,之后添加其他数据
session.add(cs)
await session.flush()
session.expunge(cs)
await TestCaseDao._insert(session, cs.id, user, data, constructor=(ConstructorDao, Constructor),
asserts=(TestCaseAssertsDao, TestCaseAsserts),
data=(PityTestcaseDataDao, PityTestcaseData))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
我们重新定义一个_insert方法(内部用的),接着把要调整的字段都用参数传入进去,这里比较好的一点是,我们的表定义都一致,比如case_id都叫case_id,创建/修改用户都叫user,否则我们的参数还得额外设计一下。
- 编写添加接口
# v2版本创建用例接口
@router.post("/create", summary="创建接口测试用例")
async def create_testcase(data: TestCaseInfo, user_info=Depends(Permission()), session=Depends(get_session)):
async with session.begin():
await TestCaseDao.insert_test_case(session, data, user_info['id'])
return PityResponse.success()
2
3
4
5
6
# 这里我没有用/v2/testcase/create这样的路由,因为v2的话,肯定是大改版了,暂时就先这样叫。注意我这里没有再用try
包裹代码了,因为我们的http中间件已经自动做了异常捕获,所以以后也都不需要这么麻烦了。
由于时间的关系,我们就暂时扩展到这里,随便测试一下:
发现没啥问题(其实中间的问题我都搞定了),收工~