最近接到到一个测试任务,某服务提供了两种登录方式:1、账号密码登录;2、手机号+验证码登录。要对这两种登录按照一定的比例进行压测。

要求:


  • 每次登录的用户不相同
  • 手机号和验证码绑定
  • 能够定位和追踪到耗时较长的请求

难点:


  • 需要每次都获取一个不同的用户
  • 每次用户验证码登录都需要获取一个验证码和一个与手机号验证码绑定的tracono
  • 需要每一次测试都有一个标记mark(非mark请求,手机号登录有两个请求)

解决方案:


  • 创建足够大的用户池,依然使用线程安全类AtomicInteger
    类来解决用户重复的线程安全问题
  • 封装两个登录方法,多一个参数区别两中登录方式
  • 参数化比例,依然使用线程安全类AtomicInteger
    类来解决每一次登录场景需要哪种登录
  • 采取mark用户id的形式来mark每一次登录

下面是测试脚本:

package com.okayqa
import com.fun.base.constaint.ThreadBaseimport com.fun.base.constaint.ThreadLimitTimeCountimport com.fun.base.interfaces.MarkThreadimport com.fun.frame.excute.Concurrentimport com.fun.utils.ArgsUtilimport com.okayqa.appmiddle.base.OkayBaseimport com.okayqa.common.OkayUsers
import java.util.concurrent.atomic.AtomicInteger
class OKAYTT extends OkayBase {
static AtomicInteger num = new AtomicInteger(0)
static AtomicInteger r = new AtomicInteger(0)
static def split;
public static void main(String[] args) {def argsUtil = new ArgsUtil(args)def thread = argsUtil.getIntOrdefault(0, 2)def time = argsUtil.getIntOrdefault(1, 5) split = argsUtil.getStringOrdefault(3, "1:2").split(":")
def threads = [] thread.times { thread << new Plus(time) }
new Concurrent(threads, "多种登录模式压测").start()

allOver() }
public static boolean getType() {def var1 = split[0] as intdef var2 = split[1] as intdef var = var1 + var2def increment = r.getAndIncrement() % varif (increment < var1) truefalse }

static class Plus extends ThreadLimitTimeCount {
int i;
public Plus(int time) {super(null, time, null)this.i = OKAYTT.num.getAndIncrement();this.mark = new Mark(OkayUsers.getStuUser(i)) }

@Overrideprotected void doing() throws Exception {new OkayBase(i, getType()) } }
static class Mark implements MarkThread {
String mark_name;
@Override String mark(ThreadBase threadBase) {return mark_name; }
public Mark(String name) {this.mark_name = name; }
public Mark() {
}
@Override MarkThread clone() {return null } }}

其中​​new OkayBase(i, getType())​​方法就是登录,第二个参数区分不同登录方法。​​i​​就是从用户池中获取的用户索引,下面是两种登录的封装方法:


public JSONObject loginPwd(String tel, int role) {        String url = LoginApi.LOGIN;        JSONObject params = getParams();        JSONObject types = new JSONObject();        types.put("type", 1);        types.put("phone", account);        types.put("pwd", pwd);        params.put("type", types);        params.put("app_id", "1");        params.put("role", role);return getPostResponse(url, params);    }
/**
* @param tel
* @param role 0家长 1学生 默认0家长
*/public JSONObject loginTel(String tel, int role) { String url = LoginApi.LOGIN; JSONObject params = getParams(); JSONObject types = new JSONObject(); types.put("type", 2); types.put("phone", tel); types.put("traceno", sendCode(tel)); types.put("code", Common.TEL_CODE); params.put("role", role); params.put("type", types);return getPostResponse(url, params);
}
public String sendCode(String tel) { String url = LoginApi.SEND_CODE; JSONObject params = getParams(); params.put("phone", tel); JSONObject response = getPostResponse(url, params); output(response);if (isRight(response)) {return response.getJSONObject("data").getString("traceno"); }return EMPTY; }

下面是密码的加密算法:

/**
* 获取加密密文
*
* @param pwd
* @return
* @throws Exception
*/protected static String getPwd(String pwd) {try { String salt = "17802ec2980353bdc3f082b0668bd1e4"; String key = StringUtils.substring(salt, 0, salt.length() / 8 * 8);// 生成一个可信任的随机数源 SecureRandom sr = new SecureRandom();// 从原始密钥数据创建DESKeySpec对象 DESKeySpec dks = new DESKeySpec(key.getBytes());// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey securekey = keyFactory.generateSecret(dks);// Cipher对象实际完成加密操作 Cipher cipher = Cipher.getInstance(DES);// 用密钥初始化Cipher对象 cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);byte[] bt = cipher.doFinal(pwd.getBytes());return new BASE64Encoder().encode(bt); } catch (Exception e) {return EMPTY; } }

在本案例中我依然采取了跟文章:​​性能测试如何减少本机误差​​中一样的方法,我把所有账号的密码都重置为相同的密码,获取统一的密码密文,取消了测试中加密密码的步骤。


  • 郑重声明:禁止第三方(腾讯云除外)转载、发表。

多种登录方式定量性能测试方案_验证码