views:

314

answers:

3

How can you simulate/stress test about 100 users accessing a given shared resource (e.g. Database) in a c# unit test?

+4  A: 

You simply cannot do useful load testing of anything via a unit test. Load testing is a separate activity with completely different goals. Your unit tests should prove that the code functions to spec. Load testing is about finding bottlenecks so you can address them.

Tom Cabanski
Ah, but you can use your unit test framework to act as your run context.
Gutzofter
A: 

I also like WAST or WCAT (do a MSDN search)

tgolisch
+1  A: 

Assuming you're accessing real DB you're in the scope of integration tests. The simplest way is to access the resource from multiple threads. For example:

[Test]
public void SimpleStressTest()
{
    bool wasExceptionThrown = false;
    var threads = new Thread[100];
    for(int i = 0; i < 100; i++)
    {
        threads[i] = 
            new Thread(new ThreadStart((Action)(() =>
            {
                try
                {                        
                    AccessDB();
                }
                catch(Exception)
                {
                    wasExceptionThrown = true;
                }

            })));
    }

    for(int i = 0; i < 100; i++)
    {
        threads[i].Start();
    }    
    for(int i = 0; i < 100; i++)
    {
        threads[i].Join();
    }

    Assert.That(wasExceptionThrown, Is.False);
}

This test is not deterministic since you can't control the threads flow. If you want to make sure, for example, that 100 connections can be opened at the same time, you can place a hook in the logic of AccessDB() which will force it to wait before it closes the connection to the DB.

For example, instead of the previous thread action:

try
{                        
    AccessDB(sychObject);
}
catch(Exception)
{
    wasExceptionThrown = true;
}

After starting all the threads make sure you have 100 threads waiting on the sychObject and only then release it and join the threads. The same can be achieved by making the logic of CloseConnection() (for example) virtual and write the test against an inheriting class the waits in CloseConnection(). For example:

public class DataBase
{
    public void AccessDB()
    {
        // Do logic here before closing connection
        CloseConnection();
    }

    protected virtual void CloseConnection()
    {
        // Real Logic to close connection
    }
}

public class FakeDataBase : DataBase
{
    ManualResetEvent sychObject;

    public FakeDataBase(ManualResetEvent sychObject)
    {
        this.sychObject = sychObject;
    }

    override protected void CloseConnection()
    {
        sychObject.WaitOne();
        base.CloseConnection();
    }
}
Elisha