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

如何通过C#服务以编程方式运行C#编写的Selenium/xUnit测试用例

.NET Framework 4.7.2 环境下C#服务运行Xunit测试的最佳实现方案

首选方案:使用Xunit官方运行器API

直接调用Xunit官方提供的运行器SDK,无需手动反射调用测试方法,也不需要启动额外的CMD进程,是最贴合需求的实现方式。

前置依赖

给你的服务项目安装兼容.NET Framework 4.7.2的Xunit运行器NuGet包,推荐使用2.4.x版本(3.0+版本仅支持.NET Core/.NET 5+,不兼容Framework):

  • xunit.runner.utility
  • xunit.extensibility.execution

核心实现示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xunit;
using Xunit.Abstractions;

// 测试结果存储结构
public class TestRunResult
{
    public string TestCaseName { get; set; }
    public bool IsPassed { get; set; }
    public string ErrorMessage { get; set; }
    public string StackTrace { get; set; }
    public double DurationMs { get; set; }
}

// 测试执行逻辑封装
public class CustomXunitRunner
{
    public List<TestRunResult> ExecuteTests(string testDllPath)
    {
        var resultList = new List<TestRunResult>();
        var testAssembly = Assembly.LoadFrom(testDllPath);
        var config = new TestAssemblyConfiguration();

        using (var xunitFramework = new XunitFramework(testAssembly))
        using (var testDiscoverer = xunitFramework.GetDiscoverer(testAssembly, config))
        using (var testExecutor = xunitFramework.GetExecutor(testAssembly))
        {
            // 发现测试程序集中所有测试用例
            var allTestCases = testDiscoverer.GetTestCases(null, null, null, null).ToList();
            // 执行测试并接收结果回调
            testExecutor.RunTests(allTestCases, new TestResultSink(resultList), new TestExecutionOptions());
        }

        return resultList;
    }
}

// 测试结果接收回调
public class TestResultSink : TestMessageVisitor<ITestCaseFinished>
{
    private readonly List<TestRunResult> _resultCollector;

    public TestResultSink(List<TestRunResult> resultCollector)
    {
        _resultCollector = resultCollector;
    }

    protected override bool Visit(ITestCaseFinished finishedMsg)
    {
        _resultCollector.Add(new TestRunResult
        {
            TestCaseName = finishedMsg.TestCase.DisplayName,
            IsPassed = finishedMsg.TestCaseStatus == TestCaseStatus.Passed,
            ErrorMessage = finishedMsg.ErrorMessage,
            StackTrace = finishedMsg.ErrorStackTrace,
            DurationMs = finishedMsg.Duration * 1000
        });
        return base.Visit(finishedMsg);
    }
}

方案优势

  • 直接在服务进程内执行测试,无额外进程开销
  • 自动兼容所有Xunit原生特性:Fact/Theory数据驱动、测试类生命周期、IClassFixture/ICollectionFixture依赖注入、测试跳过规则等,无需手动实现
  • 直接获取结构化的测试结果,无需解析控制台输出
  • 支持自定义测试过滤规则,可按需执行指定分类的测试用例

备选方案:调用xunit.console.exe子进程

如果你希望复用之前Jenkins的测试执行逻辑,可以通过C#的Process类启动xunit控制台运行器执行测试,解析输出的结果文件即可。

实现步骤

  1. 将xunit.console.exe及相关依赖和测试dll放在同一目录
  2. 启动子进程执行命令,示例参数:
    xunit.console.exe 你的测试程序集名称.dll -xml test_result.xml
  3. 等待进程执行完成后,解析输出的XML结果文件,提取测试结果

方案优势

  • 实现简单,和传统CI流程的测试执行逻辑一致,踩坑概率低
  • 测试进程和服务进程隔离,测试代码的异常不会影响服务本身的稳定性

测试结果上报实现

拿到结构化测试结果后,可按以下逻辑处理上报:

  • 统计核心指标:总用例数、通过数、失败数、跳过数、总耗时
  • 聚合所有失败用例的名称、错误信息、堆栈跟踪
  • 使用.NET Framework自带的SmtpClient类组装邮件内容,可将测试概览放在正文,完整测试结果作为附件发送

注意事项

禁止手动通过反射+try/catch调用测试方法:该方式需要自行处理测试生命周期、参数注入、特性过滤、断言异常识别等大量逻辑,极易出现测试结果不准、漏执行等问题
运行器版本必须匹配.NET Framework 4.7.2,不要使用3.0+的Xunit运行器包
如果使用子进程方案,需要确保服务运行账户有测试目录的读写权限、以及执行exe的权限

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 17:06:03