前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >“双花”BUG的测试分享

“双花”BUG的测试分享

作者头像
FunTester
发布2019-08-14 16:40:28
8390
发布2019-08-14 16:40:28
举报
文章被收录于专栏:FunTesterFunTester

“双花”一词我是从区块链领域的听到的,查了一下资料,基本所有的引用都是基于区块链,但是今天所讲的“双花”不是区块链领域,而是普通的接口测试中遇到的BUG,由于概念一致,所以采用“双花”一词。双花,顾名思义,花了两次,一分钱或者交换流通的物品。下面分享一下自己在工作中遇到的一个双花的BUG的测试方案和原因解释。

场景:有一个兑换活动,大概金币兑换礼物,金币是整个平台流通的货币,礼物价格不等。用户登录活动页后,选择不同的礼物输入数量,点击兑换。接口:活动接口两个:一、获取活动详情以及礼物详情;二、兑换一定数量礼物。兑换记录和消费记录以及个人物品都是老接口,不再赘述。测试工具:Java(不唯一),把接口提供的功能封装为方法,然后通过多线程调用封装号的方法,完成多线程请求兑换接口。

解决方案:在常规测试场景以外,利用多线程并发去测试双花BUG。主要利用了写好的性能测试框架去并发去发送某一个httprequestbase对象,通过构造对应的测试数据,检查测试完成后的测试数据,对比发现是否存在双花的BUG。

在兑换接口中,业务逻辑如下:获取用户余额,判断是否足以支付礼品总价,(大于等于时),发起扣币以及记录相关封装模块功能。

用户A,设置用户余额100,000,兑换价值100的礼物,并发1,010次。最终结果,用户余额为零,兑换的1,000个改礼物,各种记录正常。最后10次响应结果为用户余额不足。

BUG描述:在完成测试时,用户获取到的礼物数量大于1000,余额为零。最后10次请求,有一些是响应成功的。

BUG复盘,在获取完用户余额和判断完总价之后,发起扣费等业务时,并没有重新校验用户余额(或者说改过程是非原子操作不安全),这样导致了最后扣费的时候,使用的用户余额是旧的数值,其他线程也尚未完成扣费,造成了用户的一份金币,被当做两份金币消费了,也就是双花。

下面是测试代码,主要用到了自己写的测试框架,把HttpRequestBase对象组装好之后丢到trhead对象里面,设置请求次数和线程数。

package com.fission.najm.activity.before.workPractise;

import com.fission.najm.base.NajmBase;
import com.fun.frame.excute.Concurrent;
import com.fun.frame.thead.RequestThread;
import net.sf.json.JSONObject;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;

public class Exchange extends NajmBase {
	public String loginKey;
	public String exchangeCode = "";
	public int balance;
	public int coin;
	public HttpRequestBase Rechargerequest;
	public HttpRequestBase exchangeRequest;


	public static void main(String[] args) {
		NajmBase base = new NajmBase();
		Exchange exchange = new Exchange(base);
		exchange.recharge();
		RequestThread requestThread = new RequestThread(exchangeRequest, 101);
		new Concurrent(requestThread,10).start();
		allOver();
	}

	/**
	 * 充值
	 *
	 * @return
	 */
	public JSONObject recharge() {
		JSONObject response = null;
		String url = "http://www.7najm.com/cash/exchangecrecharge";
		JSONObject params = new JSONObject();
		params.put("loginKey", loginKey);
		params.put("exchangeCode", exchangeCode);
		params.put("requestType", "We");
		Rechargerequest = getHttpPost(url, params);
		//response = getHttpResponseEntityByJson(Rechargerequest);
		//output(response);
		return response;
	}

	/**
	 * 获取充值记录
	 *
	 * @return
	 */
	public JSONObject getRechargeRecord() {
		JSONObject response = null;
		String url = "http://www.7najm.com/cash/getecrrecord";
		JSONObject args = new JSONObject();
		args.put("loginKey", loginKey);
		args.put("page", 1);
		args.put("pageSize", 10);
		args.put("requestType", "Web");
		HttpGet httpGet = getHttpGet(url, args);
		response = getHttpResponseEntityByJson(httpGet);
		output(response);
		return response;
	}

	/**
	 * 获取渠道商余额
	 *
	 * @return
	 */
	public JSONObject getBalance() {
		JSONObject response = null;
		String url = "http://www.7najm.com/cash/exchangebalance";
		JSONObject args = new JSONObject();
		args.put("loginKey", loginKey);
		args.put("requestType", "Web");
		HttpGet httpGet = getHttpGet(url, args);
		response = getHttpResponseEntityByJson(httpGet);
		if (response.containsKey("dataInfo"))
			balance = response.getInt("dataInfo");
		output(response);
		return response;
	}

	/**
	 * 获取充值码
	 *
	 * @return
	 */
	public JSONObject getRechargeCode() {
		JSONObject response = null;
		String url = "http://www.7najm.com/cash/getexchangecode";
		JSONObject params = new JSONObject();
		params.put("loginKey", loginKey);
		params.put("requestType", "0");
		params.put("balance", coin);
		exchangeRequest = getHttpPost(url, params);
		response = getHttpResponseEntityByJson(exchangeRequest);
		if (response.containsKey("dataInfo")) {
			exchangeCode = response.getJSONObject("dataInfo").getString("exchangeCode");
		}
		output(response);
		return response;
	}

	/**
	 * 获取充值码列表
	 *
	 * @return
	 */
	public JSONObject getCodeRecord() {
		JSONObject response = null;
		String url = "http://www.7najm.com/cash/getecrecord";
		JSONObject args = new JSONObject();
		args.put("loginKey", loginKey);
		args.put("page", 1);
		args.put("pageSize", 20);
		args.put("requestType", "Web");
		args.put("codeType", 1);
		HttpGet httpGet = getHttpGet(url, args);
		response = getHttpResponseEntityByJson(httpGet);
		output(response);
		return response;
	}
}

往期文章精选

  1. java一行代码打印心形
  2. Linux性能监控软件netdata中文汉化版
  3. 接口测试代码覆盖率(jacoco)方案分享
  4. 性能测试框架
  5. 如何在Linux命令行界面愉快进行性能测试
  6. 图解HTTP脑图
  7. 写给所有人的编程思维
  8. 测试之JVM命令脑图
  9. 将json数据格式化输出到控制台

公众号地图 ☢️ 一起来~FunTester

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 往期文章精选
  • 公众号地图 ☢️ 一起来~FunTester
相关产品与服务
区块链
云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档