Nunit is really nice for unit testing. One thing I wanted to do in my unit test is simulate multiple users using the system. Normally it would be nice to have a set of tests for single user scenario. Once those tests pass, it is nice to be able to run them in a "multi-user" environment. I didn't really want to re-code my tests to simulate a multi-user environment, and I didn't really want to create complex threading system to do it.
So to solve the problem I used the .NET built-in thread pool, and I leverage the existing tests I have. Here is an example
Suppose we have 2 simple unit tests, one to test a customer request, and the other to test updating a customer record. The implementation is not needed for this sample.
[TestFixture] public class TestCustmoerUserCase { [Test] public void TestProcessCustmerRequest() { // processing to handle a custmer request } [Test] public void TestUpdateCustomer() { // processing to update a custmer } }
Suppose I would like to test these two scenarios in a multi-user environment. Here is one possible solution:
[TestFixture] public class TestCustmerUserCaseAsync { private delegate void AsyncDelegate(); [Test] public void TestAsync() { TestCustmoerUserCase custTest = new TestCustmoerUserCase(); // you can also run initalization code here, before starting the threads... AsyncDelegate asyncOperation = delegate { custTest.TestProcessCustmerRequest(); custTest.TestUpdateCustomer(); }; Console.WriteLine("Running thread 1"); IAsyncResult r1 = asyncOperation.BeginInvoke(null, null); Console.WriteLine("Running thread 2"); IAsyncResult r2 = asyncOperation.BeginInvoke(null, null); Console.WriteLine("Running thread 3"); IAsyncResult r3 = asyncOperation.BeginInvoke(null, null); Console.WriteLine("Waiting for threads to finish"); asyncOperation.EndInvoke(r1); Console.WriteLine("Finished thread 1"); asyncOperation.EndInvoke(r2); Console.WriteLine("Finished thread 2"); asyncOperation.EndInvoke(r3); Console.WriteLine("Finished thread 3"); } } }Lets make a few notes about the example above
- I have created a delegate using .NET C# 2.0 anonymous methods. This allows me to place a method within a method and give it a delegate name. In this case my delegate is called asyncOperation.
- Within the body of asyncOperation are the unit tests calls (which we normally call from a single thread). Note that declaring the delegate does not execute it.
- Right after declaring my delegate I ask .NET to invoke it 3 times on the thread pool. I do this with the BeginInvoke method, which each .NET delegate support.
- I pass null for callback, and null for state. That's because in this case I don't need them
- Each time a BeginInvoke is called, I get a "token" for the threaded execution called IAsyncResult. Its important to keep all 3 references I get from BeginInvoke. (in this example they are saved as r1, r2 and r3
- After launching the 3 threads. I need to wait for them to finish. Calling EndInvoke waits for the execution to finish, but which one? this is where the IAsyncResult plays an important role.
- EndInvoke(r1) will wait for the first thread to finish, EndInvoke(r2) waits for the second thread ... as so on.
- I could of used a loop and an array to store the IAsyncResults, but that would of made the example more complex. For production use, you should use a loop and array for running the threads.
So there you have it. You ran a set of unit tests that you already have without too much work. But, remember multi-threading requires a few things:
- Your unit tests need to be thread safe! its best that they don't share memory, or the small amount of memory they do share is protected between threads.
-
For more on Nunit go see http://www.nunit.org/
No comments:
Post a Comment