如何通过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.utilityxunit.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控制台运行器执行测试,解析输出的结果文件即可。
实现步骤
- 将
xunit.console.exe及相关依赖和测试dll放在同一目录 - 启动子进程执行命令,示例参数:
xunit.console.exe 你的测试程序集名称.dll -xml test_result.xml - 等待进程执行完成后,解析输出的XML结果文件,提取测试结果
方案优势
- 实现简单,和传统CI流程的测试执行逻辑一致,踩坑概率低
- 测试进程和服务进程隔离,测试代码的异常不会影响服务本身的稳定性
测试结果上报实现
拿到结构化测试结果后,可按以下逻辑处理上报:
- 统计核心指标:总用例数、通过数、失败数、跳过数、总耗时
- 聚合所有失败用例的名称、错误信息、堆栈跟踪
- 使用.NET Framework自带的
SmtpClient类组装邮件内容,可将测试概览放在正文,完整测试结果作为附件发送
注意事项
禁止手动通过反射+try/catch调用测试方法:该方式需要自行处理测试生命周期、参数注入、特性过滤、断言异常识别等大量逻辑,极易出现测试结果不准、漏执行等问题
运行器版本必须匹配.NET Framework 4.7.2,不要使用3.0+的Xunit运行器包
如果使用子进程方案,需要确保服务运行账户有测试目录的读写权限、以及执行exe的权限
内容的提问来源于stack exchange,提问作者Ben_G
相关产品推荐
相关产品推荐

