Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Stress Test - Simulate multiple access to a given shared resource

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

like image 456
Soni Ali Avatar asked Apr 20 '10 15:04

Soni Ali


1 Answers

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();
    }
}
like image 188
Elisha Avatar answered Sep 22 '22 15:09

Elisha