大家好~我是
米洛
!
我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的教程
,希望大家多多支持。
欢迎关注我的公众号米洛的测开日记
,一起交流学习!
# 写在前面
本文代码其实很多,但文字更多,主要是想讲明白现在的情况。敲者莫盲目,要一起思考。如果只是观望,那就直接看点图片了解下功能即可。
# 回顾
上一节我们编写了后端部分代码,你可能发现了一些bug,不过没关系,虽然没有自测,但是要对自己的curd有信心,实在不行,前端调试的时候,还可以改嘛~
不过由于前端比较复杂(主要是我写的臭,我就不多展示了)。大致说一下注意事项吧:
- 我们需要一个可动态伸缩的表格组件,这种事件只能自己写,或者可以采用下面这种组件:
因为这样最容易实现,但是体验没那么好(需要在modal里面编写内容,操作更繁琐)
- 由于历史原因,我们的
用例
是存在添加
态和编辑
态的,添加态指的是啥都没有,我们把用例的全部数据一次性添加到数据库,其中就包括:
用例数据 (用例表)
断言数据(断言表)
测试数据(测试数据表)
等等其他的表。但是编辑态,是我们已经存在用例数据的基础上,对其他表进行的
修改
。比如我已经有一条用例,现在要修改它,比如给它添加一条新的断言
,如果沿用添加态
的话,我们会需要更新以上N个表,十分复杂。但其实我们只需要添加一条断言数据即可。# 所以以上就是我们的历史现状,有了编辑态和添加态。在我之前设计的平台里,是把断言/前后置条件放到用例表的一个字段,所以
不存在
这样的问题。在熟悉了这2个模式之后,我们的出参提取
接口也将变得困难。其实主要就是以上2个原因吧,为了方便,我们打不算采用和之前的前后置/断言一样的模式(支持添加态和编辑态)。
为什么呢?因为添加态,添加或编辑一个断言(此时case还没有),我的逻辑是暂存断言数据,而编辑态,我们添加或编辑一个断言,需要立刻生效(入库)。为此我们增删改,大约有
6套逻辑
。有没有一种可能,去规避这些复杂逻辑,同时支持添加/编辑态呢?那就只有
批量更新
这一条路了。所谓批量更新,即把所有出参数据暂存为一个数组,无论是添加/编辑态,我们只有最后保存case的时候,才发生变化。
说简单一点就是点击
保存用例
按钮的时候,才去改变数据库,其他时候数据都都放到浏览器本地内存。但这里还有几个要注意的点:
- 历史数据的删除(比如我删除了一条旧的,添加了一条新的,我们批量更新的时候要对比)
对于这一点,简单的办法是:先删除case_id下的所有出参数据,接着全部重新添加,但这样会导致数据量越来越多(软删除),物理删除的话,会导致这个表id自增得飞快,不过影响不是很大。
- 需要用事务保证,我们必须保证所有数据都编辑完毕。
这样看起来,我们后端上次写的所谓CRUD,就没有太多作用了。因为我们可能只需要一个接口:
/parameters/update/bacth
# 改造后端
改造后的dao文件:
import time
from datetime import datetime
from typing import List
from sqlalchemy import select, update
from app.crud import Mapper
from app.middleware.RedisManager import RedisHelper
from app.models import async_session
from app.models.out_parameters import PityTestCaseOutParameters
from app.schema.testcase_out_parameters import PityTestCaseOutParametersForm
from app.utils.decorator import dao
from app.utils.logger import Log
@dao(PityTestCaseOutParameters, Log("PityTestCaseOutParametersDao"))
class PityTestCaseOutParametersDao(Mapper):
@classmethod
async def should_remove(cls, before, after):
"""
找出要删除的数据
:param before:
:param after:
:return:
"""
data = []
for b in before:
for a in after:
if a.id == b.id:
break
else:
data.append(b.id)
return data
@classmethod
@RedisHelper.up_cache("dao")
async def update_many(cls, case_id: int, data: List[PityTestCaseOutParametersForm], user_id: int):
result = []
try:
async with async_session() as session:
async with session.begin():
source = await session.execute(select(PityTestCaseOutParameters).where(
PityTestCaseOutParameters.case_id == case_id,
PityTestCaseOutParameters.deleted_at == 0,
))
before = source.scalars().all()
should_remove = await cls.should_remove(before, data)
for item in data:
if item.id is None:
# add
temp = PityTestCaseOutParameters(**item.dict(), case_id=case_id, user_id=user_id)
session.add(temp)
else:
query = await session.execute(select(PityTestCaseOutParameters).where(
PityTestCaseOutParameters.id == item.id,
))
temp = query.scalars().first()
if temp is None:
# 走新增逻辑
temp = PityTestCaseOutParameters(**item.dict(), case_id=case_id, user_id=user_id)
session.add(temp)
else:
temp.name = item.name
temp.case_id = case_id
temp.expression = item.expression
temp.source = item.source
temp.match_index = item.match_index
temp.update_user = user_id
temp.updated_at = datetime.now()
await session.flush()
session.expunge(temp)
result.append(temp)
if should_remove:
await session.execute(
update(PityTestCaseOutParameters).where(
PityTestCaseOutParameters.id.in_(should_remove)).values(
deleted_at=int(time.time() * 1000)))
return result
except Exception as e:
cls.log.error(f"批量更新出参数据失败: {e}")
raise Exception(f"批量更新出参数据失败: {e}")
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
should_remove方法,找出了应该删除的旧的数据,接着里面的内容就是批量更新
的部分:
先查出这个case下的所有出参数据
找出该删除的
遍历最新的数据,如果id存在,说明已经有数据了,有则更新,没有则新增
删除该删除的数据
以上就是方法的全过程,但采用了事务保证,所以一旦有数据失败,我们也不会改变
上一次
的数据。在最后我们返回了所有编辑好的数据(注意这里会带上新增好的id重新给予前端,前端下次请求回来也能带上具体的id)
# 添加接口
其实是不需要这个接口的,因为我们会在更新用例
的时候,顺便更新这个数据,也就不拆一个新的接口出来了。直接需要在用例form里面加上List[PityTestCaseOutParameters]字段。
同时用例表单也加入了这个字段,那这样编辑态就搞定了。接着我们还要处理添加态,注意添加case的时候,出参数据只需要新增
就好了,因为历史数据肯定不存在啊。
还记得我们编写过的一次性写入所有case数据的接口吗?
我们在这里也插入out_parameters,类似测试数据,前后置条件和断言。
这次改动内容很多,详情可看github:
# 前端调整
由于编辑态的时候,我们需要点一下编辑
按钮才能编辑case,但实际上我们改动的是下面的出参提取
数据,但让人再去点下编辑+保存,是有点太复杂了。
所以我们把接口请求里面的保存按钮,移到tab最后侧:
这样就解决了问题,我们看下crud正常不?
# 查询
查询的地方,我们也得把用例的参数数据拉取出来。
# 看看gif
# ![](https://files.mdnice.com/user/11504/d8e573d5-dd52-414b-ac41-9aa7a2a2971a.gif)
这种表单编写的体验还是远远不如pts/postman/apipost这种工具,前路慢慢,目前还能发现一些小bug,任重道远,继续努力吧。越写前端越没信心,哎~
下一期讲讲如何提取参数,以及如何使用参数。
我是米洛,一直陪伴各位学习!免费的
小黄心
,帮我点一个吧!