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

Visual Studio Web测试:如何将后台轮询请求结果纳入测试报告?

嘿,这个问题我之前做VS Web测试的时候也碰到过——线程里跑的轮询请求确实不会自动被纳入测试上下文,所以调用次数、时长这些统计自然就没进最终报告。不过有几个实用的办法能解决这个问题,咱们一个个说:

方法1:手动统计+添加测试注释

这个方法最简单,适合只需要把轮询的核心统计数据加到报告里的场景。你可以在插件里维护一个线程安全的统计变量,记录轮询请求的次数、总耗时这些信息,然后在测试结束时,通过WebTest.AddCommentToResult()把这些统计内容插入到报告的备注里。

代码示例:

public class PollingStatsPlugin : WebTestPlugin
{
    // 线程安全的统计变量,用锁保护
    private int _pollRequestCount = 0;
    private TimeSpan _totalPollDuration = TimeSpan.Zero;
    private readonly object _statsLock = new object();

    public override void PreWebTest(object sender, PreWebTestEventArgs e)
    {
        // 检查是否触发轮询的上下文参数
        if (e.WebTest.Context.ContainsKey("StartPolling"))
        {
            Task.Run(async () =>
            {
                // 轮询逻辑:直到上下文参数移除才停止
                while (e.WebTest.Context.ContainsKey("KeepPolling"))
                {
                    var stopwatch = Stopwatch.StartNew();
                    
                    // 这里替换成你实际的轮询请求发送逻辑
                    // 比如用HttpClient发送请求并处理响应
                    using (var client = new HttpClient())
                    {
                        var response = await client.GetAsync("https://your-poll-endpoint.com");
                        response.EnsureSuccessStatusCode();
                    }
                    
                    stopwatch.Stop();

                    // 更新统计数据,加锁避免线程冲突
                    lock (_statsLock)
                    {
                        _pollRequestCount++;
                        _totalPollDuration += stopwatch.Elapsed;
                    }

                    // 等待X秒后再次轮询
                    await Task.Delay(TimeSpan.FromSeconds(5));
                }
            });
        }
    }

    public override void PostWebTest(object sender, PostWebTestEventArgs e)
    {
        lock (_statsLock)
        {
            if (_pollRequestCount == 0) return;
            
            // 计算平均耗时
            var avgDurationMs = _totalPollDuration.TotalMilliseconds / _pollRequestCount;
            
            // 把统计信息添加到测试结果的注释里
            e.WebTest.AddCommentToResult(
                $"轮询请求统计:\n" +
                $"总调用次数:{_pollRequestCount}次\n" +
                $"总耗时:{_totalPollDuration.TotalSeconds:F2}秒\n" +
                $"平均耗时:{avgDurationMs:F2}毫秒"
            );
        }
    }
}

优缺点:

  • ✅ 实现简单,不需要了解复杂的VS测试结果模型
  • ❌ 只能添加文本注释,没法像普通请求那样在报告里展示详细的请求/响应信息
方法2:切换回测试上下文执行请求

这个方法更彻底——让轮询请求直接在测试的上下文线程里执行,这样VS会自动把这些请求的所有数据(调用次数、时长、响应码等)纳入报告,和普通测试请求完全一样。

核心思路是:在PreWebTest里获取测试的SynchronizationContext,然后在轮询线程里通过这个上下文把请求的执行切换回测试主线程,调用WebTest.ExecuteRequest()来发送请求。

代码示例:

public class ContextAwarePollingPlugin : WebTestPlugin
{
    private SynchronizationContext _testSyncContext;
    private WebTest _currentWebTest;
    private CancellationTokenSource _pollCts;

    public override void PreWebTest(object sender, PreWebTestEventArgs e)
    {
        _currentWebTest = e.WebTest;
        // 获取测试上下文的同步上下文
        _testSyncContext = SynchronizationContext.Current;
        _pollCts = new CancellationTokenSource();

        if (e.WebTest.Context.ContainsKey("StartPolling"))
        {
            Task.Run(async () =>
            {
                try
                {
                    while (!_pollCts.Token.IsCancellationRequested)
                    {
                        // 切换回测试上下文执行请求
                        _testSyncContext.Post(_ =>
                        {
                            // 创建轮询请求,设置URL、参数、头等信息
                            var pollRequest = new WebTestRequest("https://your-poll-endpoint.com");
                            // 比如添加请求头
                            pollRequest.Headers.Add("Authorization", $"Bearer {_currentWebTest.Context["AuthToken"]}");
                            
                            // 执行请求,这个调用会自动把结果纳入测试报告
                            _currentWebTest.ExecuteRequest(pollRequest);
                        }, null);

                        // 等待X秒后再次轮询,支持取消
                        await Task.Delay(TimeSpan.FromSeconds(5), _pollCts.Token);
                    }
                }
                catch (TaskCanceledException)
                {
                    // 轮询被取消,正常退出
                }
            }, _pollCts.Token);
        }
    }

    public override void PostWebTest(object sender, PostWebTestEventArgs e)
    {
        // 测试结束时取消轮询
        _pollCts.Cancel();
    }
}

优缺点:

  • ✅ 轮询请求完全融入测试报告,和普通请求一样展示详细数据
  • ✅ 不需要手动统计,VS自动处理所有指标
  • ⚠️ 要注意线程安全,确保测试上下文的操作不会冲突
方法3:自定义测试结果单元加入报告

如果需要完全自定义轮询请求的展示方式,可以创建WebTestResultRequest对象,手动填充请求的各项数据,然后在测试结束时把这些结果单元添加到测试的结果集合里。这个方法需要你对VS Web测试的结果对象模型有一定了解,但灵活性最高。

代码示例:

public class CustomResultPollingPlugin : WebTestPlugin
{
    private List<WebTestResultRequest> _pollResults = new List<WebTestResultRequest>();
    private readonly object _resultsLock = new object();

    public override void PreWebTest(object sender, PreWebTestEventArgs e)
    {
        if (e.WebTest.Context.ContainsKey("StartPolling"))
        {
            Task.Run(async () =>
            {
                while (e.WebTest.Context.ContainsKey("KeepPolling"))
                {
                    var startTime = DateTime.Now;
                    var stopwatch = Stopwatch.StartNew();
                    
                    // 发送轮询请求并获取响应信息
                    HttpStatusCode statusCode = HttpStatusCode.OK;
                    try
                    {
                        using (var client = new HttpClient())
                        {
                            var response = await client.GetAsync("https://your-poll-endpoint.com");
                            statusCode = response.StatusCode;
                        }
                    }
                    catch (Exception ex)
                    {
                        // 处理请求异常,比如标记为失败
                        statusCode = HttpStatusCode.InternalServerError;
                    }
                    
                    stopwatch.Stop();
                    var endTime = startTime.Add(stopwatch.Elapsed);

                    // 创建自定义的测试结果请求对象
                    var pollResult = new WebTestResultRequest(new WebTestRequest("https://your-poll-endpoint.com"))
                    {
                        ResponseStatusCode = (int)statusCode,
                        Duration = stopwatch.Elapsed,
                        StartTime = startTime,
                        EndTime = endTime,
                        // 可以设置更多属性,比如响应大小、请求方法等
                        Method = "GET"
                    };

                    // 线程安全地添加到结果列表
                    lock (_resultsLock)
                    {
                        _pollResults.Add(pollResult);
                    }

                    await Task.Delay(TimeSpan.FromSeconds(5));
                }
            });
        }
    }

    public override void PostWebTest(object sender, PostWebTestEventArgs e)
    {
        lock (_resultsLock)
        {
            // 把所有自定义结果添加到测试结果集合里
            foreach (var result in _pollResults)
            {
                e.WebTestResult.ResultUnits.Add(result);
            }
        }
    }
}

优缺点:

  • ✅ 完全自定义结果的各项属性,满足特殊展示需求
  • ✅ 结果会像普通请求一样出现在报告的请求列表里
  • ❌ 实现相对复杂,需要熟悉VS测试结果的对象结构

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:00:08