16

I'm pretty new to unit testing and currently experimenting a bit with Visual Studio's testing tools.

My question is how to define assertions about concurrent behaviour in these tests. E.g. given a class BoundedChan<T> implementing a bounded channel, how can I specify tests like

  1. "channel.Send will not block" or
  2. "If the channel's capacity is exceeded, channel.Send will block until a value is read"

Is there an elegant solution to write these assertions?

Dario
  • 48,658
  • 8
  • 97
  • 130
  • 1
    I'm not sure there are any precise duplicates (though this one is close: http://stackoverflow.com/questions/314580/how-do-i-perform-a-unit-test-using-threads), but there's quite a bit of good SO material on this. I've listed some of the better discussions in my response here: http://stackoverflow.com/questions/1520539/how-to-prove-that-multithreading-is-working/1520619#1520619. – Jeff Sternal Jan 08 '10 at 18:06
  • @Jeff: Why don't you post this as an answer - Looks quite useful to me. – Dario Jan 08 '10 at 18:28

3 Answers3

7

Unfortunately, concurrency is still an area of unit testing that is challenging to structure easily. It's not a simple problem, and still requires that you implement some of your own synchronization and concurrency logic in the test.

For the example you provide, it may be impossible to write a test that conclusively demonstrates that a method will or won't block under certain conditions. You may be able to achieve some level of confidence by first creating worst-case circumstances where you would expect the blocking behavior - and then write tests to determine if that occurs or not.

Here's a blog article that discusses the topic; it focuses on NUnit.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
LBushkin
  • 129,300
  • 32
  • 216
  • 265
  • 2
    Link is dead, but Wayback Machine has your back. Original Dan Barvitsky article: https://web.archive.org/web/20140822013404/http://www.atalasoft.com/cs/blogs/danbarvitsky/archive/2009/06/12/techniques-for-testing-concurrent-code-in-nunit.aspx . His follow up post: https://web.archive.org/web/20100526080326/http://www.atalasoft.com/cs/blogs/danbarvitsky/archive/2009/06/15/my-solution-for-unit-testing-concurrent-code-in-nunit.aspx . – Søren Boisen May 30 '15 at 14:10
6

This question could lead to enough content to fill a book.

In general, I would not recommend adding unit tests to your classes for concurrent scenarios. With practice I think you'll learn that automated unit tests have one or several "sweet spots" -- and that focusing your efforts in these areas (and using other practices in other areas) yields better ROI.

But your class seems to be about concurrency (can't tell for certain based on info provided), and therefore this could be a case where you really want a concurrency-simulating test.

You can (as far as I know) start up multiple threads in a unit test if you wish. But there may be a simpler way. Consider leveraging the Compose Method pattern. While we're on the subject -- this pattern is pretty critical to effective unit tests over all, not just with concurrency.

Drew Wills
  • 8,408
  • 4
  • 29
  • 40
1

I have created a helper that can start a bunch of threads to execute concurrent actions. The helper provides synchronization primitives and logging mechanisms. It can be used in conjunction with any unit test framework. Here is a code fragment from a unit test:

[Test]
public void TwoCodeBlocksInParallelTest()
{
    // This static method runs the provided Action delegates in parallel using threads
    CTestHelper.Run(
        c =>
            {
                Thread.Sleep(1000); // Here should be the code to provide something 
                CTestHelper.AddSequenceStep("Provide"); // We record a sequence step for the expectations after the test
                CTestHelper.SetEvent();
            },
        c =>
            {
                CTestHelper.WaitEvent(); // We wait until we can consume what is provided
                CTestHelper.AddSequenceStep("Consume"); // We record a sequence step for the expectations after the test
            },
        TimeSpan.FromSeconds(10)); // This is a timeout parameter, if the threads are deadlocked or take too long, the threads are terminated and a timeout exception is thrown 

    // After Run() completes we can analyze if the recorded sequence steps are in the correct order
    Expect(CTestHelper.GetSequence(), Is.EqualTo(new[] { "Provide", "Consume" }));
}

It can be used to test client/server or synchronization in components or simply run a thread with a timeout. I'll continue to improve this in the next weeks. Here is the project page: Concurrency Testing Helper

Thomas Maierhofer
  • 2,665
  • 18
  • 33