I have a method that contains an asynchronous call like this:
public void MyMethod() {
...
(new Action<string>(worker.DoWork)).BeginInvoke(myString, null, null);
...
}
I'm using Unity and creating mock objects is not a problem, but how can I test that DoWork is called without worrying about race conditions?
A previous question offers a solution, but it seems to me that wait-handles is a hack (the race condition is still there, although it should be virtually impossible to raise).
EDIT: Okay, I thought I could ask this question in a very general manner, but it seems I have to elaborate further on the problem:
I want to create a test for the above mentioned MyMethod, so I do something like this:
[TestMethod]
public void TestMyMethod() {
...setup...
MockWorker worker = new MockWorker();
MyObject myObj = new MyObject(worker);
...assert preconditions...
myObj.MyMethod();
...assert postconditions...
}
The naïve approach would be to create a MockWorker() that simply sets a flag when DoWork has been called, and test that flag in the postconditions. This would of course lead to a race condition, where the postconditions are checked before the flag is set in the MockWorker.
The more correct approach (which I'll probably end up using) is using a wait-handle:
class MockWorker : Worker {
public AutoResetEvent AutoResetEvent = new AutoResetEvent();
public override void DoWork(string arg) {
AutoResetEvent.Set();
}
}
...and use the following assertion:
Assert.IsTrue(worker.AutoResetEvent.WaitOne(1000, false));
This is using a semaphore-like approach, which is fine... but in theory the following could happen:
- BeginInvoke is called on my DoWork delegate
- For some reason neither the main-thread or the DoWork-thread is given execution time for 1000ms.
- The main-thread is given execution time, and because of the timeout the assertion fails, even though the DoWork thread is yet to be executed.
Have I misunderstood how AutoResetEvent works? Am I just being too paranoid, or is there a clever solution to this problem?