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

如何在.NET Core 3.1的C#控制台程序中输入stop立即终止NUnit测试?

解决NUnit测试即时终止的问题

你的问题在于之前的代码是在测试执行完成后才会触发Console.ReadLine()——主线程被测试运行完全阻塞了,根本没机会实时监听输入。要实现输入"stop"就立即终止测试,需要单独开一个线程监听控制台输入,同时还要能控制NUnit的测试执行流程,而不是等测试跑完再杀进程。下面给你两种可行的方案:

方案一:使用NUnit Engine API(推荐,优雅终止)

这种方法直接通过NUnit的编程式API运行测试,让你可以主动调用停止方法,不需要粗暴杀死进程。

步骤:

  1. 先安装NUnit Engine的NuGet包:

    Install-Package NUnit.Engine
    Install-Package NUnit.Engine.Api
    

    注意选择和.NET Core 3.1兼容的版本(比如3.13.x系列)。

  2. 编写代码,后台线程监听输入,收到stop时终止测试:

    using System;
    using System.Threading;
    using NUnit.Engine;
    
    namespace TestRunnerApp
    {
        class Program
        {
            static ITestRunner _testRunner;
    
            static void Main(string[] args)
            {
                // 启动后台线程监听控制台输入
                var inputListenerThread = new Thread(ListenForStopCommand);
                inputListenerThread.IsBackground = true;
                inputListenerThread.Start();
    
                // 初始化NUnit测试引擎
                var testEngine = TestEngineActivator.CreateInstance();
                var testPackage = new TestPackage(@"你的测试项目.dll路径");
    
                // 启动测试
                _testRunner = testEngine.GetRunner(testPackage);
                var testResult = _testRunner.Run(null); // null使用默认的测试结果输出
    
                // 测试结束后清理资源
                _testRunner.Dispose();
                testEngine.Dispose();
            }
    
            static void ListenForStopCommand()
            {
                while (true)
                {
                    var input = Console.ReadLine();
                    if (input?.Trim().Equals("stop", StringComparison.OrdinalIgnoreCase) == true)
                    {
                        Console.WriteLine("收到停止命令,正在终止测试...");
                        // 立即终止测试,true表示不等待当前测试完成
                        _testRunner?.StopRun(true);
                        break;
                    }
                }
            }
        }
    }
    

说明:

  • 后台线程会一直监听控制台输入,不会阻塞主线程的测试运行。
  • StopRun(true)方法会立即终止所有正在运行的测试,而不是等它们完成,完美满足你的即时终止需求。
  • 这种方式属于优雅终止,不会像Kill()那样直接杀死整个进程,能保证测试引擎做必要的资源清理。

方案二:外部进程运行dotnet test(适合必须用命令行的场景)

如果你坚持要通过dotnet test命令启动测试,那需要找到测试对应的子进程并杀死它(因为dotnet test会启动testhost子进程来实际运行测试)。

步骤:

  1. 安装System.Management NuGet包,用来获取进程的子进程:

    Install-Package System.Management
    
  2. 编写代码,启动dotnet test进程并监听输入:

    using System;
    using System.Diagnostics;
    using System.Management;
    using System.Threading;
    
    namespace TestRunnerApp
    {
        class Program
        {
            static Process _dotnetTestProcess;
    
            static void Main(string[] args)
            {
                // 启动输入监听线程
                var inputThread = new Thread(ListenForStopCommand);
                inputThread.IsBackground = true;
                inputThread.Start();
    
                // 启动dotnet test进程
                _dotnetTestProcess = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName = "dotnet",
                        Arguments = "test",
                        WorkingDirectory = @"你的测试项目根目录",
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true
                    }
                };
    
                _dotnetTestProcess.Start();
    
                // 实时输出测试日志到控制台
                _dotnetTestProcess.OutputDataReceived += (sender, e) => Console.WriteLine(e.Data);
                _dotnetTestProcess.ErrorDataReceived += (sender, e) => Console.WriteLine(e.Data);
                _dotnetTestProcess.BeginOutputReadLine();
                _dotnetTestProcess.BeginErrorReadLine();
    
                // 等待测试进程结束
                _dotnetTestProcess.WaitForExit();
            }
    
            static void ListenForStopCommand()
            {
                while (true)
                {
                    var input = Console.ReadLine();
                    if (input?.Trim().Equals("stop", StringComparison.OrdinalIgnoreCase) == true)
                    {
                        Console.WriteLine("收到停止命令,正在终止测试进程...");
                        KillProcessAndChildren(_dotnetTestProcess.Id);
                        break;
                    }
                }
            }
    
            // 递归杀死进程及其所有子进程
            static void KillProcessAndChildren(int pid)
            {
                // 获取所有子进程
                using (var searcher = new ManagementObjectSearcher($"SELECT * FROM Win32_Process WHERE ParentProcessID={pid}"))
                {
                    foreach (var obj in searcher.Get())
                    {
                        var childPid = Convert.ToInt32(obj["ProcessID"]);
                        KillProcessAndChildren(childPid);
                    }
                }
    
                try
                {
                    var process = Process.GetProcessById(pid);
                    process.Kill();
                }
                catch (ArgumentException)
                {
                    // 进程已经结束,忽略异常
                }
            }
        }
    }
    

说明:

  • 这个方法会启动dotnet test作为子进程,同时实时输出测试日志。
  • 收到stop命令时,会递归杀死dotnet test进程及其子进程(也就是实际运行测试的testhost进程),确保测试完全终止。
  • 这种方式是强制杀死进程,不如方案一优雅,但适合必须使用dotnet test命令的场景。

总结

优先选择方案一,因为它能通过NUnit的原生API控制测试流程,实现优雅的即时终止,避免进程被强制杀死带来的潜在问题。如果因为某些原因必须用dotnet test命令,再考虑方案二。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 08:07:47