我的开发日记(九)

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

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

  • 有好多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

热文精选

posted @   FunTester  阅读(131)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示