Search code examples
c#.netmultithreadingnunitsemaphore

NUnit and testing in different threads


I'm testing an application. A [TearDown] methods contains another method which sends a request a server. This one is pretty slow. Meanwhile a server is unable to handle more than 3 requests at the same time.

So I decided to use a semaphore.

   [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);
        }
    } 

However it seems like it does not work properly. Now in log file on a server there are no records, which means a server does not receive any requests.

1) What did I do wrong?

2) How do I initialize a semaphore:

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

or

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

Solution

  • 1) What did I do wrong?

    The test runner is probably ending the test process before the thread has finished (or even started). You can verify it using something like Fiddler to verify there is no communication between the test and the server.

    Is there a reason why you need to run it in a separate thread? Unless you are specifically testing threaded code, avoid it because it just creates complexities. Call it as you would normally. It also means any exception or error thrown will be caught by the test runner and reported in the test results.

    If a test is taking too long (and you cannot fix the root cause like the server speed) consider an IoC container like AutoFac or reference counting to share this between tests that need it. Also consider running the tests in parallel, too.

    2) How do I initialize a semaphore:

    The first argument to the Semaphore class constructor is the initial number of requests. In this case, you probably want to initialize it to 0 since you have no requests running initially.

    Note that a semaphore may help the test not send more than three requests but it will not help the server if tests are running concurrently but you probably realise that.