1.浮点型计算导致精度丢失
产品需求:违约金减免金额不能大于违约金。违约金为后端计算,违约金减免金额为用户输入。
后端实现:后端数据库存的金额已分为单位,金额在数据库中存为整型。后端只接收整型的违约金金额。
前端实现:前端输入的违约金减免金额为浮点型,限制小数点后两位。前端传给后端时,需要给违约金减免金额*100,然后将违约金减免金额与违约金进行比较。
遗漏原因:不清楚前后端交互逻辑,未考虑到浮点型计算会精度丢失问题。
导致问题:
(1) 违约金后端存112时,前端输入1.12,根据需求:112=1.12*100.应该是可以通过校验的。前端经过计算,违约金减免金额为:112.00000000000001,此时前端报错,提示违约金减免金额不能大于违约金。
(2) 违约金后端存113,前端输入1.13,根据需求:113=1.13*100.应该是可以通过校验的。此时数据传到后端为112.99999999999999,后端报错,提示违约金减免金额不为整型。
具体前后端交互代码如下所示:
#!usr/bin/env python
#-*- coding:utf-8 -*-
"""
@author:doulihang
@file: test.py
@time: 2019/07/12
"""
def compare(num1,num2):
"""
:param num1: 违约金金额
:param num2: 违约金减免金额
:return:
"""
#对违约金减免金额*100
num2 = num2*100
#前端校验违约金减免金额与违约金的关系
if num1 < num2:
print("违约金(%s)小于违约金减免金额(%s)"%(num1,num2))
#前端校验通过,后端接收整型的违约金减免金额
elif "."not in str(num2) or ("." in str(num2) and str(num2).endswith('0')):
print("违约金减免金额(%s)为整型合法,可以入库"%num2)
else:
print("违约金减免金额(%s)非整型,不能入库"%num2)
compare(258,2.58)
compare(113,1.13)
compare(112,1.12)
代码执行结果:
解决方法,前端对违约金减免金额*100后,进行四舍五入。
修改后代码:
#!usr/bin/env python
#-*- coding:utf-8 -*-
"""
@author:doulihang
@file: test.py
@time: 2019/07/12
"""
def compare(num1,num2):
"""
:param num1: 违约金金额
:param num2: 违约金减免金额
:return:
"""
#对违约金减免金额*100
#对违约金减免金额进行四舍五入
num2 = round(num2*100)
#前端校验违约金减免金额与违约金的关系
if num1 < num2:
print("违约金(%s)小于违约金减免金额(%s)"%(num1,num2))
#前端校验通过,后端接收整型的违约金减免金额
elif "."not in str(num2) or ("." in str(num2) and str(num2).endswith('0')):
print("违约金减免金额(%s)为整型合法,可以入库"%num2)
else:
print("违约金减免金额(%s)非整型,不能入库"%num2)
compare(258,2.58)
compare(113,1.13)
compare(112,1.12)
代码执行结果:
2.批量审批导致不该更新的数据进行更新
产品需求:批量审批时,如果请款金额为0,将该条工单状态置为无需请款,金额不为0,状态置为待请款
后端实现:如果请款金额为0,将某个字段置为False,如果该字段为False,那么就将该条工单状态置为无需请款
遗漏原因:不清楚此处逻辑,测试用例设计时,未考虑到此问题,已有批量更新数据时,需要注意此类问题。
导致问题:批量审批时,金额为0的工单及其之后所有的工单,状态都会被置为无需请款
具体后端代码演示:
def batch_approval(data):
"""
:param data:待审批列表,每个下标对应一条工单,amount为金额,
status为工单状态,0:待审批,-1:无需请款,1:待请款
:return: data:审批后的工单
"""
is_payout = True
for index,value in enumerate(data):
if value['amount'] == 0:
is_payout = False
if is_payout == False:
value['status'] = -1
else:
value['status'] = 1
return data
data = [
{'amount':1, 'status':0},
{'amount':0, 'status':0},
{'amount':10, 'status':0},
]
print(batch_approval(data))
代码执行结果:
我们可以看出,程序会将金额不为0的工单状态置为无需请款
解决方法:在每一轮for循环都将is_payout变量重置为Ture
修改后代码:
def batch_approval(data):
"""
:param data:待审批列表,每个下标对应一条工单,amount为金额,
status为工单状态,0:待审批,-1:无需请款,1:待请款
:return: data:审批后的工单
"""
for index,value in enumerate(data):
#每次for循环都将is_payout初始化为true
is_payout = True
if value['amount'] == 0:
is_payout = False
if is_payout == False:
value['status'] = -1
else:
value['status'] = 1
return data
data = [
{'amount':1, 'status':0},
{'amount':0, 'status':0},
{'amount':10, 'status':0},
]
print(batch_approval(data))
修改后代码执行结果: