本文为博主原创,未经授权,严禁转载及使用。
本文链接:https://blog.csdn.net/zyooooxie/article/details/118969591
之前分享过一期 抽奖【一】 关注点:多用户抽奖、抽奖结果、积分的变动,现在把后续的这篇补上;
【实际这篇博客推迟发布N个月】
个人博客:https://blog.csdn.net/zyooooxie
【以下所有内容仅为个人项目经历,如有不同,纯属正常】
需求2
某实物大抽奖活动的规则是:用户通过某渠道获取抽奖机会;每次开奖,随机中奖;中奖后 不可以再抽(前端不再展示抽奖页面);实物奖品数量有限,先到先得;
测试时,我的关注点:中奖概率、奖品库存。
这个抽奖不是每次都中奖,幸运的用户 抽中后 才发放奖品;所以用户中奖概率是要配置的;
假设 中奖概率是 与抽奖次数相关,配置 如下:
"lotteryConfig":[{"rate":0.1,"minLotteryCount":0,"maxLotteryCount":50},{"rate":1,"minLotteryCount":51,"maxLotteryCount":100}]
抽奖配置:总次数<= 50次 每次抽奖中奖概率在0.1%;总次数在51-100次 每次抽奖中奖概率在1%;未配置的区间 每次抽奖中奖概率在0.01%;
【说的是 每次抽 中奖的概率,不是某次抽 的中奖概率】
简单举例:
抽奖次数为2,每次概率为0.1%;抽奖次数为33,每次概率为0.1%;
抽奖次数为66次,每次概率是1%;抽奖次数为99次,每次概率是1%;
抽奖次数为144次,每次概率为0.01%;抽奖次数为255次,每次概率为0.01%;
测试点:中奖概率
假设 后台配置是:{“rate”:10,“minLotteryCount”:0,“maxLotteryCount”:999999}【测试过程中,中奖概率不变】
我的思路:
- 准备N个用户的数据:有资格参与活动、已选了某实物奖品、当前有抽奖次数10次;
- 每个用户登录活动页,抽10次(抽中的,直接break:抽中后 再抽,接口返回值是抽中,但实际不会再计入),统计其数据(未中奖次数+中奖次数);
- 对 此N个用户的数据 做修改:清理已中奖的信息,再给抽奖次数10次;
- 循环第2、3步,统计每一轮的中奖次数、抽奖总次数;把数据存入Excel,UAT时可做展示;抽奖脚本可现场执行,看结果;
(代码有删改)
def read_txt_file(use_rows: int, file: str = 'b_g_h.txt', skip_rows: int = None):
"""
读取txt文件的用户信息
:param use_rows:
:param file:
:param skip_rows:
:return:
"""
data = pd.read_csv(file, encoding='utf-8', skiprows=skip_rows, nrows=use_rows, names=['userId', 'phone'])
all_data_list = data.values.tolist()
user_id_list = list()
mobile_list = list()
for d in data.values:
user_id_list.append(d[0])
mobile_list.append(d[1])
return all_data_list, user_id_list, mobile_list
def test_lottery(user_id: str, phone: int):
"""
抽奖
:param user_id:
:param phone:
:return:
"""
Log.info('{}-登录活动页'.format(phone))
s = requests.Session()
url = 'https://blog.csdn.net/zyooooxie/genSession'
data = {'mobile': phone, "scene": 666}
res = s.post(url, json=data, verify=False)
res_dict = res.json()
assert res_dict['obj']['userId'] == user_id
code_list = list()
for i in range(10):
url1 = 'https://blog.csdn.net/zyooooxie~lottery'
res1 = s.post(url1, json={}, verify=False)
code = res1.json()['obj']['Code']
Log.debug('抽的幸运码:{}'.format(code))
# 抽中
if code == '9999': # 中奖码
assert res1.json()['obj']['awardStatus'] == 1
code_list.append(code)
fail_times = i
return code_list, fail_times
fail_times = 10
return code_list, fail_times
def main_insert():
"""
抽奖前-让用户有资格参与抽奖
:return:
"""
db_m_1, cur_m_1 = connect_db()
all_data_1, user_list_1, phone_list_1 = read_txt_file(100)
# insert_SETTING_TASK_TYPE(user_list_1, phone_list_1)
for ad in all_data_1:
insert_SETTING_TASK_TYPE(ad[0], ad[1], db_m_1, cur_m_1)
insert_PACKET_TASK_TYPE(ad[0], ad[1], db_m_1, cur_m_1)
insert_ADD_COUNT_TASK_TYPE(ad[0], ad[1], db_m_1, cur_m_1)
else:
cur_m_1.close()
db_m_1.close()
def main_lottery():
"""
抽奖
:return:
"""
fail_times_list = list()
success_times_list = list()
all_data, user_list, phone_list = read_txt_file(100)
for ad in all_data:
run = test_lottery(ad[0], ad[1])
ft = run[1]
if run[1] == 10:
Log.info('没中')
fail_times_list.append(ft)
elif len(run[0]) != 0:
Log.info('中了')
fail_times_list.append(ft)
success_times_list.append(1)
else:
raise Exception('test_lottery() 返回 有问题')
Log.info('在这一轮中 抽中的次数 {}'.format(sum(success_times_list)))
Log.info('在这一轮中 总次数 {}'.format((sum(fail_times_list) + sum(success_times_list))))
def main_lottery2():
"""
抽完-修改抽奖次数、删除中奖数据
:return:
"""
db_m_2, cur_m_2 = connect_db()
all_data, user_list, phone_list = read_txt_file(100)
for ad in all_data:
# add_member_grade(ad[0])
update_ADD_COUNT_TASK_TYPE(ad[0], ad[1], db_m_2, cur_m_2)
delete_EXCHANGE_PACKET_TASK_TYPE(ad[0], ad[1], db_m_2, cur_m_2)
else:
Log.info('修改抽奖次数、删除中奖信息 done')
cur_m_2.close()
db_m_2.close()
Excel 计算公式 :=A10/B10、=SUM(B9:B48)
测试点:奖品库存、并发抽奖
在我看来,实物奖品库存 实际有三种情景:
- 用户抽奖时,库存多得是;
这其实就是前面 中奖概率;
在test_lottery() 中奖的情况下 实际还有个断言(关于中奖礼品的断言,被我删掉了);
- 用户抽奖时,库存已经发光了;
这部分的设计是 隐瞒用户抽中实物了,但没有库存 发放失败 的事实;
so 返回的Code是 幸运码外 的随机数字【真实测试时,为了验证方便,可以让后台同事写死 为0000】;
- 实物库存快发光了,多位用户同时抢着抽;
实际我测得时候是JMeter脚本 设置了50个用户,抢1个库存;
每个用户 先登录,再去抽10次,抽奖接口使用的是 抽中了9999 做断言;
本文链接:https://blog.csdn.net/zyooooxie/article/details/118969591
交流技术 欢迎+QQ 153132336 zy
个人博客 https://blog.csdn.net/zyooooxie