「原创声明:保留所有权利,禁止转载」
在我做接口测试的工作中,有段时间负责产品的每星期活动的接口测试,需求一般比较简单,但是有一批活动很特殊,在之前的工作中都没遇到过,就是概率型业务。常见的抽奖、随机奖励、用户分组等等。都涉及到概率,接口单次返回结果并不可预期,只有经过大量统计得到的结果才具有参考性,也不具有决定性。对于这类接口的测试,当时存在着两个难点:一、如何判断业务实现结果符合预期;二、如何才算发现其中 BUG。总结来说就是如何判断概率准确性。
我以一个之前负责过的老虎机的活动为例,分享一下当时的解决方案和实践经验。
需求:用户花费一定量的金币可以得到一次抽奖机会,每次抽奖有 4 种(可配置)类型的礼物,以及一定概率的未中奖概率(等于 1-中奖概率之和),为了简化过程每种礼物的中奖概率以 1% 位单位。
接口:三个接口:一、抽奖接口;二、获取活动配置接口(包括各类礼物配置和信息);三、个人活动详情(个人信息、抽奖次数、获奖情况)
测试工具:Java(不唯一),通过把三个接口提供的功能封装为方法,然后通过方法调用去获取数据,进而统计得到的结果。
测试时间:一天。
两个难点的解决方案:
- 如何判断业务实现结果符合预期 业务实现结果即是大量测试统计结果,预期是后台配置的各类事件的概率。举个简单的例子,如果 A 事件发生概率为 10%,那么在 10000 次测试中,发生 N 次 A 事件,就认为 A 事件发生的概率为 10%,求 N 的取值范围。 首先在本次举例中,事件概率的颗粒度为 1%,那么问题就转化为如何区别两个事件发生概率 1% 的事件。在经过一些讨论和尝试,我们采取了一个公式:如果独立事件发生概率颗粒度 a,那么进行 a 平方的倒数次测试,事件实际发生的次数与理论值误差小于颗粒度的 1/2,即认为该事件实际发生概率等于理论值。 本例中如果 A 时间设置的发生概率等于 10%,那么进行 10000 次测试,如果 A 时间发生概率在 950-1050 次之间,那么 A 时间发生概率等于 10%。
- 如何才算发现其中的 BUG 解决了第一个难点,第二个难点就有了一部分答案,设置发生概率,然后进行测试,统计结果,对比数据。如果发现不符合预期,则视为 BUG,当然保险起见,还是要进行足够多的测试。因为概率学告诉我们:如果进行足够多的测试,那么测试结果实际值会更接近理论值,参考投针试验。 另外一个答案就是构造不可能发生的事件和一定会发生的事件来进行足够多的测试,发现 BUG。这个比较简单,比如我们把某一个事件的概率设置为 0% 或者 100%,然后不停地做测试,如果该事件偶尔发生了一次/偶尔没有发生,那么这绝对是一个 BUG。这里计算足够多的次数,依然采取了上面的公式,使用概率颗粒度平方倒数。
在实际的测试当中,由于接口测试时间比较短,执行单次测试用例的时间会很长,需要采取其他的手段来达到缩短时间的目的。当时才用了一个思路:多线程。一、使用多线程去跑不同的用例,达到整体测试时间缩短的目的;二、使用多线程跑同一个用例,达到单次用纸执行时间缩短的目的。在第二个方面,需要用到 Java 多线程中线程安全的知识,不然很难统计到真实的数据。
- 总结一下,这类需求其实应该直接白盒测试的。
下面分享一下当时测试代码,比较糙乱,多线程测试类代码找不到了,见谅!
package com.fission.najm.activity.before.workPractise;
import com.fission.najm.base.NajmBase;
import net.sf.json.JSONObject;
import org.apache.http.client.methods.HttpGet;
public class Tiger extends NajmBase {
public long aa = getDate().getTime();
public String url = "http://haahi.7najm.com/service/activity/v3/32";
// public String url = "http://www.7najm.com/service/activity/v3/32";
public String loginKey;
// public String userId = "898542";// 中东用户 id
public int pay = 4;
public int freeType = 2;
// public String userId = "879136";// 土耳其用户 id
public static int feather;// 羽毛
public static int addFeather;// 增加羽毛数
public static int addGift;// 增加礼物数
public static int times;// 次数
public static int type;// 结果类型
public static int giftId;// 礼物 id
public static int code;// 礼物 id
public static JSONObject gifts = new JSONObject();
public static JSONObject types = new JSONObject();
public Tiger() {
this.loginKey = loginNajm(1);
}
public static void main(String[] args) {
Tiger tigger = new Tiger();
// tigger.refresh();
tigger.getUserInfo();
// int sss = 0;
// while (times < 100) {
// output(times);
// if (code == 1101)
// sss++;
// times++;
// sleep(1);
// tigger.testLucky();
// // countCount(types, type);
// // if (feather != 0)
// // addFeather++;
// // if (giftId != 0) {
// // countCount(gifts, giftId);
// // addGift++;
// // }
// }
outputLine();
output(types);
output(gifts);
output(addFeather);
output(times);
// output(sss);
// tigger.getLuckys();
testOver();
}
public JSONObject getUserInfo() {
JSONObject args = new JSONObject();
args.put("loginKey", loginKey);
args.put("type", 1);
HttpGet httpGet = getHttpGet(url, args);
JSONObject response = getHttpResponseEntityByJson(httpGet);
output(response);
return response;
}
public JSONObject testLucky() {
JSONObject args = new JSONObject();
args.put("loginKey", loginKey);
args.put("pay", pay);
args.put("freeType", freeType);// 是否是免费1免费 2付费
args.put("type", 2);
HttpGet httpGet = getHttpGet(url, args);
HttpGet httpGet = getHttpGet(url, args);
JSONObject response = getHttpResponseEntityByJson(httpGet);
if (response != null && response.containsKey("dataInfo")) {
feather = response.getJSONObject("dataInfo").getInt("feather");
type = response.getJSONObject("dataInfo").getInt("type");
giftId = response.getJSONObject("dataInfo").getInt("giftId");
} else {
feather = 0;
type = 0;
giftId = 0;
}
code = response.getInt("code");
output(response);
return response;
}
public JSONObject getLuckys() {
JSONObject args = new JSONObject();
args.put("loginKey", loginKey);
args.put("type", 3);
HttpGet httpGet = getHttpGet(url, args);
JSONObject response = getHttpResponseEntityByJson(httpGet);
return response;
}
public JSONObject refresh() {
JSONObject args = new JSONObject();
args.put("loginKey", loginKey);
args.put("type", 4);
HttpGet httpGet = getHttpGet(url, args);
JSONObject response = getHttpResponseEntityByJson(httpGet);
return response;
}
}
- 郑重声明:文章首发于公众号 “FunTester”,欢迎关注交流,禁止第三方(腾讯云除外)转载、发表。
技术类文章精选
- Linux 性能监控软件 netdata 中文汉化版
- 性能测试框架第三版
- 图解 HTTP 脑图
- 性能测试中图形化输出测试数据
- 压测中测量异步写入接口的延迟
- 多种登录方式定量性能测试方案
- JMeter 吞吐量误差分析
- 多项目登录互踢测试用例
无代码文章精选
- 写给所有人的编程思维
- JSON 基础
- 2020 年 Tester 自我提升
- 自动化新手要避免的坑(上)
- 自动化新手要避免的坑(下)
- 如何成为全栈自动化工程师
- 选择手动测试还是自动化测试?
- 自动化测试项目为何失败
- 简化测试用例
TesterHome 为用户提供「保留所有权利,禁止转载」的选项。
除非获得原作者的单独授权,任何第三方不得转载标注了「原创声明:保留所有权利,禁止转载」的内容,否则均视为侵权。
具体请参见TesterHome 知识产权保护协议。
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
暂无回复。