Backend Development 8 min read

Implementing Asynchronous Test Case Execution with Thread Pool in Java

This article explains how to design and implement a multithreaded framework for executing test cases concurrently in Java, covering thread‑pool creation, a runnable test‑case class, collection execution logic, and parameter handling with user credentials and random data generation.

FunTester
FunTester
FunTester
Implementing Asynchronous Test Case Execution with Thread Pool in Java

The author describes a solution for asynchronously executing test cases and collecting results, which involves creating a thread pool, designing multithreaded objects, and running multiple test cases in parallel while handling shared user credentials.

Multithreaded Test Case Class

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: 完成基本功能的初始化
    }
}

Thread Pool Utility

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
(1000));
    }
}

Running a Collection of Test Cases

@Override
    public CollectionRunSimpleResutl runCollection(RunCollectionBean bean) {
        List
cases = getCasesDeatil(bean);
        CountDownLatch countDownLatch = new CountDownLatch(cases.size());
        int andIncrement = OkayConstant.COLLECTION_MARK.getAndIncrement();
        List
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
> collect = results.stream()
                .map(x -> x.getRecord().getResult())
                .collect(Collectors.groupingBy(x -> x));
        CollectionRunSimpleResutl res = new CollectionRunSimpleResutl();
        // todo: 初始化res
        return res;
    }

Fetching and Preparing Test Cases

@Override
    public List
getCasesDeatil(RunCollectionBean bean) {
        ConcurrentHashMap
certificates = new ConcurrentHashMap<>();
        List
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;
    }

Parameter Handling with User Certificates and Random Values

@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
map) {
        JSONObject params = bean.getParams();
        JSONObject headers = bean.getHeaders();
        handleParams(params, map);
        handleParams(headers, map);
    }

    /**
     * 处理参数中的表达式信息
     * @param params
     */
    public void handleParams(JSONObject params) {
        params.keySet().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])));
            }
        });
    }

    public void handleParams(JSONObject params, ConcurrentHashMap map) {
        params.keySet().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])));
            }
        });
    }

The author notes that asynchronous storage of run records keeps total execution time under ten seconds, making the test‑case collection run quickly without requiring users to wait long after triggering execution.

backendJavaconcurrencythreadpoolmultithreadingTestAutomation
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.