FunTester 我的开发日记 (九)

FunTester · 2020年06月25日 · 796 次阅读

昨天由于有个项目上线,所以通了个宵,今早起来比较晚,工作进度又落下来一截,心里更加慌慌了。这两天的主要任务还是搬砖了,只有一个地方值得记一下,就是异步执行测试用例,并收集结果。其中涉及到了线程池的创建,基本多线程对象的设计,多用例并行执行。这里面用到的多个用例如果同时使用同一个用户的登录凭证和用户登录凭证缓存。

我的基本方案如下:先用多线程把用例里面的使用到的用户凭证替换成真正的值,然后再去将处理好的用例信息丢给线程池去执行,然后等待所有的线程执行完,测试结果处理等等。

  • 有好多TODO内容,过完端午节补上。

多线程类

package com.okay.family.common;

import com.okay.family.common.basedata.OkayConstant;
import com.okay.family.common.bean.testcase.CaseRunRecord;
import com.okay.family.common.bean.testcase.request.CaseDataBean;
import com.okay.family.common.enums.RunResult;
import com.okay.family.common.exception.CommonException;
import com.okay.family.common.exception.UserStatusException;
import com.okay.family.utils.RunCaseUtil;

import java.util.concurrent.CountDownLatch;

public class CaseRunThread implements Runnable {

    int runId;

    CaseDataBean bean;

    CaseRunRecord record;

    CountDownLatch countDownLatch;

    public CaseRunRecord getRecord() {
        return record;
    }

    private CaseRunThread() {

    }

    public CaseRunThread(CaseDataBean bean, CountDownLatch countDownLatch, int runId) {
        this.bean = bean;
        this.countDownLatch = countDownLatch;
        this.runId = runId;
        this.record = new CaseRunRecord();
    }

    @Override
    public void run() {
        try {
            record = RunCaseUtil.run(bean);
        } catch (UserStatusException e) {
            record.setResult(RunResult.USER_ERROR.getCode());
        } catch (CommonException e) {
            record.setResult(RunResult.UNRUN.getCode());
        } catch (Exception e) {
            record.setResult(RunResult.UNRUN.getCode());
        } finally {
            countDownLatch.countDown();
        }
    }

    private void init() {
        record.setMark(OkayConstant.RUN_MARK.getAndIncrement());
        record.setRunId(runId);
        record.setCaseId(bean.getId());
        //todo:完成基本功能的初始化
    }


}

线程池类

比较简单,具体功能还得后续完善。

package com.okay.family.common;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class OkayThreadPool {

    private static ThreadPoolExecutor executor = createPool();

    public static void addSyncWork(Runnable runnable) {
        executor.execute(runnable);
    }

    private static ThreadPoolExecutor createPool() {
        return new ThreadPoolExecutor(5, 50, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(1000));

    }

}

执行用例集的具体方法

@Override
public CollectionRunSimpleResutl runCollection(RunCollectionBean bean) {
    List<CaseDataBean> cases = getCasesDeatil(bean);
    CountDownLatch countDownLatch = new CountDownLatch(cases.size());
    int andIncrement = OkayConstant.COLLECTION_MARK.getAndIncrement();
    List<CaseRunThread> results = new ArrayList<>();
    String start = Time.getDate();
    cases.forEach(x -> {
        CaseRunThread caseRunThread = new CaseRunThread(x, countDownLatch, andIncrement);
        OkayThreadPool.addSyncWork(caseRunThread);
        results.add(caseRunThread);
    });
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        CommonException.fail("执行用例集失败!");
    }
    String end = Time.getDate();
    //todo:处理结果,记录结果,返回结果
    results.forEach(x -> caseService.addRunRecord(x.getRecord()));
    Map<Integer, List<Integer>> collect = results.stream().map(x -> x.getRecord().getResult()).collect(Collectors.groupingBy(x -> x));
    CollectionRunSimpleResutl res = new CollectionRunSimpleResutl();
    //todo:初始化res

    return res;
}

处理用例中的用户凭证和参数的方法

@Override
public List<CaseDataBean> getCasesDeatil(RunCollectionBean bean) {
    ConcurrentHashMap<Integer, String> certificates = new ConcurrentHashMap<>();
    List<CaseDataBean> cases = caseCollectionMapper.getCasesDeatil(bean);
    CountDownLatch countDownLatch = new CountDownLatch(cases.size());
    cases.forEach(x -> {
        new Thread(() -> {
            try {
                caseService.handleParams(x, certificates);
            }finally {
                countDownLatch.countDown();
            }
        }).start();
    });
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        CommonException.fail("初始化用例信息失败!");
    }
    return cases;
}

下面是caseService.handleParams方法内容,参数带map的都是多线程用的

@Override
public void handleParams(CaseDataBean bean) {
    JSONObject params = bean.getParams();
    JSONObject headers = bean.getHeaders();
    handleParams(params);
    handleParams(headers);
}

@Override
public void handleParams(CaseDataBean bean, ConcurrentHashMap<Integer, String> map) {
    JSONObject params = bean.getParams();
    JSONObject headers = bean.getHeaders();
    handleParams(params, map);
    handleParams(headers, map);
}

/**
 * 处理参数中的表达式信息
 *
 * @param params
 */
public void handleParams(JSONObject params) {
    params.keySet().stream().forEach(key ->
    {
        String value = params.getString(key);
        if (value.startsWith(OkayConstant.USER_CERTIFICATE_KEY)) {
            int id = SourceCode.changeStringToInt(value.substring(OkayConstant.USER_CERTIFICATE_KEY.length()));
            TestUserCheckBean userCheckBean = testUserService.getCertificate(id);
            params.put(key, userCheckBean.getCertificate());
        } else if (value.startsWith(OkayConstant.RANDOM_KEY)) {
            String replace = value.replace(OkayConstant.RANDOM_KEY, Constant.EMPTY);
            String[] split = replace.split(",", 2);
            params.put(key, SourceCode.getRandomIntRange(SourceCode.changeStringToInt(split[0]), SourceCode.changeStringToInt(split[1])));
        }
    });
}

/**
 * 处理参数中的表达式信息
 *
 * @param params
 */
public void handleParams(JSONObject params, ConcurrentHashMap map) {
    params.keySet().stream().forEach(key ->
    {
        String value = params.getString(key);
        if (value.startsWith(OkayConstant.USER_CERTIFICATE_KEY)) {
            int id = SourceCode.changeStringToInt(value.substring(OkayConstant.USER_CERTIFICATE_KEY.length()));
            String certificate = testUserService.getCertificate(id, map);
            params.put(key, certificate);
        } else if (value.startsWith(OkayConstant.RANDOM_KEY)) {
            String replace = value.replace(OkayConstant.RANDOM_KEY, Constant.EMPTY);
            String[] split = replace.split(",", 2);
            params.put(key, SourceCode.getRandomIntRange(SourceCode.changeStringToInt(split[0]), SourceCode.changeStringToInt(split[1])));
        }
    });
}

  • 一般存储运行记录我都会用异步,所以基本上算下来,运行时间应该在 10s 以内,用例集的运行会很快。不用点击运行之后,还得等一会儿才能看到结果。

  • 公众号FunTester首发,欢迎关注,禁止第三方擅自转载,合作请联系Fhaohaizi@163.com

热文精选

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册