我想编写一个调用某些异步产品任务的同步测试。
在下面的示例中,DoSomething()由单独的线程调用,然后设置SomethingCompleted事件。
在我的测试代码中,如何设置SomethingCompleted?
public event Action<Result> SomethingCompleted;
public void DoSomething()
{
Something();
this.SomethingCompleted(new Result("Success"));
}
答案 0 :(得分:2)
using (var evt = new ManualResetEvent()) {
Action<Result> handler = _ => evt.Set();
SomethingCompleted += handler;
evt.WaitOne();
SomethingCompleted -= handler; //cut object reference to help GC
}
如果需要,您可以在等待完成后取消订阅活动。这样,事件不会使委托和闭包实例保持活动状态。
您可以将其解压缩为可重复使用的辅助方法/扩展名。
答案 1 :(得分:0)
// 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();
}
如何订阅活动并“轮询”lambda直到结果可用?这应该有用。
答案 2 :(得分:0)
您使用的是错误类型的事件。您正在使用的事件是回调。在您提供的代码中,附加到SomethingCompleted
事件的代理将在与DoSomething
相同的线程上调用。
您想要的是使用AutoResetEvent
或ManualResetEvent
之类的事件进行线程同步,这与您正在使用的框架/语言级事件无关。你可以这样做:
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();
}
这只是众多不同方法中的一种。替代方案包括并行LINQ或任务并行库(两者最好用于并行操作,而不仅仅是单个后台操作)。如果您不想阻止主线程,请查看BackgroundWorker
。