.net NUnit和不同线程中的测试

zpgglvta  于 2023-04-22  发布在  .NET
关注(0)|答案(3)|浏览(119)

我正在测试一个应用程序。一个[TearDown]方法包含了另一个向服务器发送请求的方法。这个方法非常慢。同时一个服务器不能同时处理3个以上的请求。
所以我决定使用信号量。

[TestFixture]
    public class TestBase
    {
        private const int MaxThreadsCount = 3;
        private readonly Semaphore _semaphore = new Semaphore(MaxThreadsCount, MaxThreadsCount);

        [SetUp]
        public virtual void Setup()
        {
        }

        [TearDown]
        public void CleanUp()
        {
            //...some code
            new Thread(_ => SendRequestAsync("url/of/a/server", parameters)).Start();
        }

        private void SendRequestAsync(string url, NameValueCollection parameters)
        {
            _semaphore.WaitOne();
            string result = MyServerHelper.SendRequest(url, parameters); 
            Assert.That(string.IsNullOrEmpty(result), Is.False, "SendRequest returned false");
        }

        [Test]
        public void Test01()
        {
            Assert.AreEqual(1, 1);
        }

        [Test]
        public void Test02()
        {
            Assert.AreEqual(1, 1);
        }

        [Test]
        public void Test03()
        {
            Assert.AreEqual(1, 1);
        }
        //...........................
        [Test]
        public void TestN()
        {
            Assert.AreEqual(1, 1);
        }
    }

然而,它似乎不能正常工作。现在在服务器上的日志文件中没有记录,这意味着服务器没有收到任何请求。
1)我做错了什么?
2)如何初始化信号量:

private readonly Semaphore _semaphore = new Semaphore(MaxThreadsCount, MaxThreadsCount);

private readonly Semaphore _semaphore = new Semaphore(0, MaxThreadsCount);
mhd8tkvw

mhd8tkvw1#

1)我做错了什么?
测试运行器可能在线程完成(甚至启动)之前就结束了测试进程。您可以使用类似Fiddler的东西来验证它,以验证测试和服务器之间没有通信。
有什么原因需要在单独的线程中运行它吗?除非你专门测试线程代码,否则避免它,因为它只会增加复杂性。像平常一样调用它。这也意味着任何抛出的异常或错误都会被测试运行器捕获并在测试结果中报告。
如果一个测试花费的时间太长(并且你无法修复根本原因,比如服务器速度),可以考虑使用AutoFac或引用计数这样的IoC容器,在需要它的测试之间共享它。还可以考虑运行in parallel测试。
2)如何初始化信号量:
Semaphore class constructor的第一个参数是请求的初始数量。在本例中,您可能希望将其初始化为0,因为您最初没有运行任何请求。
请注意,信号量可能有助于测试不发送超过三个请求,但如果测试同时运行,它对服务器没有帮助,但您可能意识到这一点。

xpcnnkqh

xpcnnkqh2#

我的理解是,单元测试应该测试小的功能单元。你不应该需要创建多个线程来让你的测试工作。如果你有缓慢的外部依赖(如网络连接或数据库);你可以定义接口来抽象它。
你应该能够在没有线程的情况下测试你想要的行为。我们可以假设线程工作-我们担心你的代码。假设在你的代码中的某个地方你有一个计数器,它指示活动连接或请求的数量;或者确定您是否可以接受另一连接的某种其他方式。
你想测试当一个请求进来时会发生什么,当你已经达到最大值时。
因此,编写一个测试来实现这一点,将计数器设置为max,调用开放连接代码,并验证它是否失败,并出现预期的错误。

3phpmpom

3phpmpom3#

在某些情况下,您希望使用测试框架来运行集成测试,这些测试包含启动多个线程的冗长操作和进程。
然后,您测试的OFC将运行,直到它启动一个新线程或等待一个长任务,然后在整个进程执行之前测试突然结束。
Thread.Sleep的问题是它非常类似于Cargo Cult编程。您将决定让测试运行至少一定的时间,这可能会根据运行测试的机器而有所不同,如果每个人都使用这种策略,您的持续构建系统将不会非常快。
这里有一个更好的解决方案:

[Test]
public async Task TestWithTimeOut()
{
    //You can set a very long timeout here
    var timeOut = TimeSpan.FromSeconds(10);

    var testExecutionTask = new Task(
        () =>
        {               
            //Test execution and assertion goes here        
            //it should not contain await - use .GetAwaiter().GetResult() instead if needed
        });
        
    var timeoutTask = Task.Delay(timeOut).ContinueWith(_=> throw new TimeoutException());
    
    Func<Task> f = () => Task.WhenAny(testExecutionTask, timeoutTask);
    
    await f.Should().NotThrowAsync();
};

相关问题