You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用TestNG测试基于ForkJoinPool的REST服务异步调用

用TestNG测试基于ForkJoinPool的REST服务异步调用逻辑

嘿,我来帮你一步步搞定这个测试!针对你用ForkJoinPool实现的异步调用逻辑,咱们可以从依赖隔离、场景覆盖、结果验证这几个角度来设计TestNG测试用例,下面具体说:

一、准备工作:Mock依赖服务

首先,咱们得把service1和service2给Mock掉,避免测试依赖真实的数据库或外部服务。推荐用Mockito配合TestNG,你只需要在项目里引入对应的依赖包就行。

二、核心测试场景与代码示例

1. 测试正常异步执行场景

这个场景要验证两个任务都被正确提交、执行,并且返回结果符合预期,同时中间的其他操作不会被阻塞。

import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.List;
import static org.mockito.Mockito.*;
import static org.testng.Assert.*;

public class ForkJoinAsyncServiceTest {

    // 被测类(假设你的异步逻辑封装在这个类里)
    private AsyncServiceUnderTest asyncService;

    @Mock
    private Service1 service1;
    @Mock
    private Service2 service2;

    private ForkJoinPool testForkJoinPool;
    private Filter filter;  // 假设你的过滤参数类

    @BeforeMethod
    public void setup() {
        MockitoAnnotations.openMocks(this);
        // 创建自定义ForkJoinPool,方便控制并行度,避免测试间干扰
        testForkJoinPool = new ForkJoinPool(2);
        asyncService = new AsyncServiceUnderTest(testForkJoinPool, service1, service2);
        filter = new Filter();  // 初始化测试用的过滤参数
    }

    @Test
    public void testAsyncTasksExecuteSuccessfully() {
        // 1. 准备Mock返回值
        List<Something> mockResult1 = Arrays.asList(new Something("item1"), new Something("item2"));
        List<Something> mockResult2 = Arrays.asList(new Something("item3"), new Something("item4"));
        when(service1.findAll(filter)).thenReturn(mockResult1);
        when(service2.findAll(filter)).thenReturn(mockResult2);

        // 2. 执行被测逻辑
        asyncService.executeAsyncTasks(filter);

        // 3. 等待异步任务完成并获取结果
        // 这里假设被测类会保存任务引用,或者你可以通过返回值获取任务实例
        ForkJoinTask<List<Something>> task1 = asyncService.getSomeJoinTask1();
        ForkJoinTask<List<Something>> task2 = asyncService.getSomeJoinTask2();
        List<Something> result1 = task1.join();
        List<Something> result2 = task2.join();

        // 4. 验证结果与调用行为
        assertEquals(result1, mockResult1);
        assertEquals(result2, mockResult2);
        verify(service1, times(1)).findAll(filter);
        verify(service2, times(1)).findAll(filter);

        // 5. 验证中间的「其他操作」是否正常执行
        assertTrue(asyncService.isOtherOperationExecuted());
    }
}

2. 测试异步任务不阻塞主线程

这个场景要确保提交ForkJoin任务后,主线程能继续执行后续操作,不需要等待任务完成。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.testng.annotations.Test;
import static org.mockito.Mockito.*;
import static org.testng.Assert.*;

@Test
public void testMainThreadNotBlocked() throws InterruptedException {
    // 用CountDownLatch监听任务完成信号
    CountDownLatch taskLatch = new CountDownLatch(2);
    
    // Mock service方法,模拟耗时操作
    when(service1.findAll(filter)).thenAnswer(invocation -> {
        Thread.sleep(1000);
        taskLatch.countDown();
        return Arrays.asList(new Something("item1"));
    });
    when(service2.findAll(filter)).thenAnswer(invocation -> {
        Thread.sleep(1000);
        taskLatch.countDown();
        return Arrays.asList(new Something("item2"));
    });

    // 记录开始时间,验证后续操作是否立即执行
    long startTime = System.currentTimeMillis();
    asyncService.executeAsyncTasks(filter);
    long operationTime = System.currentTimeMillis() - startTime;
    assertTrue(operationTime < 500, "后续操作被异步任务阻塞了");

    // 等待任务完成,避免测试提前结束
    taskLatch.await(3, TimeUnit.SECONDS);
}

3. 测试异常场景

如果某个service调用抛出异常,要验证任务的异常处理逻辑是否符合预期(比如是否捕获异常、是否影响另一个任务)。

@Test(expectedExceptions = RuntimeException.class)
public void testTaskFailurePropagates() {
    // Mock service1抛出异常
    when(service1.findAll(filter)).thenThrow(new RuntimeException("Service1 failed"));
    when(service2.findAll(filter)).thenReturn(Arrays.asList(new Something("item3")));

    // 执行被测逻辑
    asyncService.executeAsyncTasks(filter);

    // 获取任务结果,触发异常(TestNG的expectedExceptions会验证这个异常)
    ForkJoinTask<List<Something>> task1 = asyncService.getSomeJoinTask1();
    task1.join();
}

三、关键注意事项

  • 自定义ForkJoinPool:测试时尽量用自己创建的ForkJoinPool,不要用默认公共池,避免不同测试间的线程干扰。
  • 任务等待方式:可以用ForkJoinTask.join()阻塞获取结果,或者用ForkJoinPool.awaitQuiescence()等待所有任务结束。
  • Mock细节:如果service方法是耗时操作,用thenAnswer模拟延迟,更贴近真实业务场景。
  • 线程安全:如果被测类里的任务引用是共享变量,要注意测试方法间的隔离,避免互相干扰。

内容的提问来源于stack exchange,提问作者Angel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:37:00