测试基础 无意中发现的一个线上 BUG 说起

JoyMao · 2022年08月10日 · 最后由 JoyMao 回复于 2022年08月12日 · 5135 次阅读

除了日常测试,还兼着 FineBI 上数据运维的工作。一个新版本功能上线后,运营需要我提供对应的运营数据,我就向开发咨询对应业务及提供对应 sql 给我参考

原业务复杂其关联多表,但概括来说就是有个查询第三方商品价格记录表 [T]:
|log_id| sku_id | price | delete_flag | add_time |

为了便于理解,补充说明下:

  • 因为价格会变化,所以会定时去调用接口增量生成新的记录,log_id 是每次查询结果 ID,是主键;
  • 每条记录会被二次校验,如不合适,会置删除标志:

需求是:获取每个 SKU 没删除的最新的价格信息(注:没有相同的 add_time)

一般这种分组排序取最新,oracle 或 impala 的查询 sql 通常都用:
row_number() over(partition by sku_id order by add_time desc) as rn ...where delete_flag=0
然后筛选 rn=1 来做。
不能用这类函数的,可以用下面这种通用写法:
select *
from T t0
join (select sku_id,max(add_time) max_add_time from T where delete_flag=0 group by sku_id) t1
on t0.sku_id=t1.sku_id and t0.add_time=t1.max_add_time

而开发将其对应功能列表的 sql 发给参考,却是类似是这种:
select t0.*
from T t0
where t0.delete_flag=0
and not exists (select * from T t1 where t1.sku_id=t0.sku_id and t1.add_time>t0.add_time)

开发说不要用那个麻烦分组排序,用这个就行了......

其实,虽然这段时间一直和 sql 打交道,但也确实没想过用 not exists 来实现类似的分组取最新的场景。
但这个 sql 却是有问题的:

  1. not exists 会进行主表全扫描,如果很大,性能势必有新影响,但这个不是我关心的。
  2. sql 的结果有 BUG:not exists 后表没有加上条件 delete_flag=0,也就是外表和内表不是同条件的。

那么, 如果存在这样的数据,sku_id-123 就会查询不到:

log_id sku_id price delete_flag add_time
11111 123 10.2 0 2022-08-01 01:01:01
11200 123 10.3 1 2022-08-02 01:01:01

无法确定测试人员为啥没有测出该 BUG,可能是凭经验过于相信开发(是个老开发),用了简单方式:从既有的列表结果来看是否最新的。

而我也自省了一番:如果是我,会不会也会遗漏?

  1. 这是个小需求点(相对于此版本的其他功能),会不会花心思好好设计一番测试场景:还只是简单看下既有的列表结果?
  2. 从场景设计出发,最容易想出以下场景:
    • 删除的记录不显示
    • 有效的记录显示
    • 1 个 sku 有多个有效记录时取最新的...

你看,从需求角度正向设计用例场景很自然也很习惯,很容易就这样了。

而 “1 个 sku 既有有效,也有无效,且无效的时间大于有效的时间” 这类场景则需要对这个需求点再上点心。

工作多年了,经历瀑布 - 敏捷-DevOps 的过程:为了赶时间,现在不少测试工作都是凭经验来,虽然没出过啥岔子,但也从这个例子上吸取了点教训。

  1. 再小的需求规则都要好好设计测试场景,勿要随意
  2. 有能力的话,还是得看看开发的代码
最佳回复

首先问个问题:为什么同一个 ID 在不同表有不同的删除状态的情况?这是特殊需求要求,还是设计缺陷或者运维错误导致的数据错误?

如果这是个很明确的需求(从数据层面看,是最新加的数据被删除了,所以最新应该取上一个版本的数据),那么可以理解是漏测,但可能很难被发现。从设计角度也很奇怪,如果一张表里有很多同一个商品 ID 的记录,而且只会有一个价格是生效的,那么应该给它加标记,而不是通过是否被删除加时间排序来筛选。就好像价格一直在波动,我可能需要把昨天新加的价格挂上来,也可能把上个月新加的价格挂上来。这种情况下是不是直接去更新这个标记更保险也更直观?

而如果是后者,我觉得把责任往测试身上推就很勉强了。

共收到 7 条回复 时间 点赞

这是个 BUG 吗?

Thirty-Thirty 回复

可能我没说明白或你没细看:
那个开发给我的参考 sql 就是他开发的列表用的,那个 sql 会造成上文举例的那个 SKU 无法显示,这样不是 BUG?

JoyMao 回复

发现这个问题后,你提 BUG 单了吗?或者,收到你反映的这个问题后,测试人员提 BUG 单了吗?

首先问个问题:为什么同一个 ID 在不同表有不同的删除状态的情况?这是特殊需求要求,还是设计缺陷或者运维错误导致的数据错误?

如果这是个很明确的需求(从数据层面看,是最新加的数据被删除了,所以最新应该取上一个版本的数据),那么可以理解是漏测,但可能很难被发现。从设计角度也很奇怪,如果一张表里有很多同一个商品 ID 的记录,而且只会有一个价格是生效的,那么应该给它加标记,而不是通过是否被删除加时间排序来筛选。就好像价格一直在波动,我可能需要把昨天新加的价格挂上来,也可能把上个月新加的价格挂上来。这种情况下是不是直接去更新这个标记更保险也更直观?

而如果是后者,我觉得把责任往测试身上推就很勉强了。

Jerry li 回复

我在原文加上了补充说明,这样就能明白了。
另外,价格是从第 3 方获取的,但有二次校验(UPC、产品名...校验),校验不通过会被删除。
为啥要保留历史数据?这个是为了 BI 分析用的,看价格的历史变动用的。

至于增加一个生效标志,这个设计完全看开发的个人设计喜好了:

  • 加这个标志需要在插入时多做一些步骤
  • 不加的话则需要查询的时候麻烦些

对于测试来说,符合需求就 OK 了,只不过这里开发耍了一个 “技巧” 耍撇了...

至于责任,那是因为我也是测试,遗漏 bug 时首先会考虑自己的问题,而把责任推给测试那就言重了,毕竟 BUG 是开发写的。

3楼 已删除
Thirty-Thirty 回复

这个是本职工作呀

我写本文的初衷是讨论怎样避免一些测试遗漏,比如这里:

  1. 是不是用例设计的时候可以就避免了
  2. 或者能不能先去了解开发写的代码设计、sql 一类 等等

歪楼了...

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册