I want to write a synchronous test that calls into some asynchronous product tasks.
In the example below, DoSomething() is called by a separate thread, and then it sets the SomethingCompleted event.
In my test code, how do I wait for SomethingCompleted to be set?
public event Action<Result> SomethingCompleted;
public void DoSomething()
{
Something();
this.SomethingCompleted(new Result("Success"));
}
using (var evt = new ManualResetEvent()) {
Action<Result> handler = _ => evt.Set();
SomethingCompleted += handler;
evt.WaitOne();
SomethingCompleted -= handler; //cut object reference to help GC
}
If required you can unsubscribe from the event after the wait has completed. That way the event will not keep the delegate and closure instance alive.
You can extract this into a reusable helper method/extension.
// test case
public void Test()
{
var yourObj = new YourObj();
var done = false;
Result result;
yourObj.SomethingCompleted += (finalResult) => {
result=finalResult;
done=true;
};
yourObj.DoSomething();
while(!done) Thread.Sleep(200);
if(result != theExpectedResult) kaboom();
}
What about subscribing to an event and "polling" the lambda until result comes available? This should work.
You're using the wrong type of event. The event you're using is a callback. In the code you supplied, the delegates attached to the SomethingCompleted
event are going to be called on the same thread as DoSomething
.
What you want is thread synchronization, using an event like AutoResetEvent
or ManualResetEvent
, which have nothing to do with the framework/language-level event that you're using. You could do something like this:
void MainThreadProc()
{
// create thread synchronization event
using (var evt = new ManualResetEvent(false))
{
// start background operation
ThreadPool.QueueUserWorkItem(BackgroundThreadProc, evt);
// this line will block until BackgroundThreadProc sets the event
evt.WaitOne();
}
// resume main thread operations here
...
}
void BackgroundThreadProc(object o)
{
// get event from argument
var evt = (ManualResetEvent) o;
// do the deed
...
// set event to signal completion
evt.Set();
}
This is just one of a number of different ways to do this. Alternatives include Parallel LINQ or the Task Parallel Library (both of which are best used with parallel operations, not just a single background operation). If you don't want to block the main thread, look at BackgroundWorker
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.