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

如何在NUnit中自动并行运行两个测试实现跨地址空间Socket通信?

实现跨进程并行测试的自动化方案

要实现单个测试触发两个独立地址空间的Test1和Test2并行运行,核心思路是在主测试中启动两个独立的NUnit测试进程,分别执行Test1和Test2。这样两个测试会运行在不同进程中,拥有各自的地址空间,完全满足真实网络通信的模拟需求。

具体步骤:

  1. 标记独立测试为显式执行:给Test1和Test2加上[Explicit]属性,避免它们被常规测试套件自动执行,只能通过指定命令触发。
  2. 主测试中启动独立进程:在主测试方法里,通过Process.Start()调用dotnet test(或nunit-console.exe),分别指定运行Test1和Test2。
  3. 同步与结果验证:等待两个测试进程完成,通过临时文件、命名管道等方式收集测试结果,在主测试中完成断言。

代码示例:

定义独立的Test1和Test2:

using NUnit.Framework;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace YourTestNamespace
{
    [TestFixture]
    public class NetworkProtocolTests
    {
        // 测试服务器角色,仅显式触发
        [Test, Explicit]
        public void Test1_ServerSide()
        {
            var listener = new TcpListener(IPAddress.Loopback, 8888);
            listener.Start();
            
            using var client = listener.AcceptTcpClient();
            using var stream = client.GetStream();
            // 读取客户端数据,验证协议逻辑
            var buffer = new byte[1024];
            var bytesRead = stream.Read(buffer, 0, buffer.Length);
            var receivedData = System.Text.Encoding.UTF8.GetString(buffer, 0, bytesRead);
            
            // 模拟响应
            var response = System.Text.Encoding.UTF8.GetBytes("ACK:" + receivedData);
            stream.Write(response, 0, response.Length);
            
            // 将验证结果写入临时文件
            File.WriteAllText(Path.Combine(Path.GetTempPath(), "server_result.txt"), 
                receivedData == "PROTOCOL_TEST_DATA" ? "ServerValidationPassed" : "ServerValidationFailed");
            
            listener.Stop();
        }

        // 测试客户端角色,仅显式触发
        [Test, Explicit]
        public void Test2_ClientSide()
        {
            using var client = new TcpClient();
            client.Connect(IPAddress.Loopback, 8888);
            
            using var stream = client.GetStream();
            // 发送协议测试数据
            var testData = System.Text.Encoding.UTF8.GetBytes("PROTOCOL_TEST_DATA");
            stream.Write(testData, 0, testData.Length);
            
            // 读取响应
            var buffer = new byte[1024];
            var bytesRead = stream.Read(buffer, 0, buffer.Length);
            var response = System.Text.Encoding.UTF8.GetString(buffer, 0, bytesRead);
            
            // 将验证结果写入临时文件
            File.WriteAllText(Path.Combine(Path.GetTempPath(), "client_result.txt"), 
                response == "ACK:PROTOCOL_TEST_DATA" ? "ClientValidationPassed" : "ClientValidationFailed");
        }
    }
}

主测试(触发跨进程并行执行):

using NUnit.Framework;
using System.Diagnostics;
using System.IO;
using System.Reflection;

namespace YourTestNamespace
{
    [TestFixture]
    public class AutomatedCrossProcessTest
    {
        [Test]
        public void RunCrossProcessProtocolTest()
        {
            // 初始化临时文件路径
            var serverResultPath = Path.Combine(Path.GetTempPath(), "server_result.txt");
            var clientResultPath = Path.Combine(Path.GetTempPath(), "client_result.txt");
            
            // 清理旧文件
            File.Delete(serverResultPath);
            File.Delete(clientResultPath);

            // 获取测试项目工作目录
            var workingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            // 启动服务器测试进程
            var serverProcess = Process.Start(new ProcessStartInfo
            {
                FileName = "dotnet",
                Arguments = $"test --filter FullyQualifiedName={typeof(NetworkProtocolTests).FullName}.Test1_ServerSide",
                WorkingDirectory = workingDir,
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true
            });

            // 启动客户端测试进程(延迟1秒确保服务器已启动,可根据实际调整)
            System.Threading.Thread.Sleep(1000);
            var clientProcess = Process.Start(new ProcessStartInfo
            {
                FileName = "dotnet",
                Arguments = $"test --filter FullyQualifiedName={typeof(NetworkProtocolTests).FullName}.Test2_ClientSide",
                WorkingDirectory = workingDir,
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true
            });

            // 等待两个进程完成
            serverProcess?.WaitForExit();
            clientProcess?.WaitForExit();

            // 读取结果并断言
            Assert.That(File.Exists(serverResultPath), Is.True, "Server test did not generate result");
            Assert.That(File.Exists(clientResultPath), Is.True, "Client test did not generate result");

            var serverResult = File.ReadAllText(serverResultPath);
            var clientResult = File.ReadAllText(clientResultPath);

            Assert.That(serverResult, Is.EqualTo("ServerValidationPassed"));
            Assert.That(clientResult, Is.EqualTo("ClientValidationPassed"));

            // 清理临时文件
            File.Delete(serverResultPath);
            File.Delete(clientResultPath);
        }
    }
}

注意事项:

  • 端口冲突处理:如果需要多次运行,建议通过命令行参数动态传递端口号,避免硬编码端口导致冲突。
  • 进程同步优化:示例中用Thread.Sleep()做简单同步,生产环境可以用更可靠的方式(比如让服务器监听端口成功后写入标记文件,客户端检测到标记再启动)。
  • 结果传递方式:除了临时文件,还可以用命名管道、共享内存或本地HTTP接口传递结果,效率更高。
  • 异常处理:实际代码中要添加进程启动失败、文件读取失败的异常捕获逻辑,确保测试稳定性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 15:45:43