我有一个设置,其中更改类的变量引发异步运行的事件,我尝试单元测试。单元测试异步事件
class A {
Action<int> OnIntChange;
private int _a;
public int a {
set {
OnIntChange(value);
}
}
}
class B {
RaiseAsyncEvent(int value) {
Task.Factory.StartNew(() => {c = value;});
}
int c;
}
以前的一切是同步的,所以很容易地我能单元测试:
B b = new B();
A.OnIntChange += b.RaiseAsyncEvent;
A.a = 10;
Assert.AreEqual(10, A.b.c);
但是现在这个失败。我不能使用ManualResetEvents,因为我没有直接提出这个事件,并且不能没有代码重组。看来我唯一的选择是在调用A.a = 10之后添加一个System.Threading.Thread.Sleep()调用,但我正在寻找其他选项。建议?
~~~~~~~~~~编辑~~~~~~~~
我在寻找一个潜在的解决方案是让RaiseAsyncEvent返回它创建的任务和字段设置到任务。喜欢的东西:
class B {
Task task;
RaiseAsyncEvent(int value) {
task = Task.Factory.StartNew(() => {c = value;});
}
int c;
}
B b = new B();
A.OnIntChange += b.RaiseAsyncEvent;
b.task.Wait();
A.a = 10;
Assert.AreEqual(10, A.b.c);
~~~~~~~~~~进一步编辑~~~~~~~~~~
我最终什么事做这是改变B到解决以下:
class B {
bool RunAsync = true;
RaiseAsyncEvent(int value) {
Task task = Task.Factory.StartNew(() => {c = value;});
if(!RunAsync) { task.Wait();}
}
int c;
}
,并改变了测试:
B b = new B();
b.RunAsync = false;
A.OnIntChange += b.RaiseAsyncEvent;
A.a = 10;
Assert.AreEqual(10, A.b.c);
我喜欢这个答案,我将它标记为已接受的答案 - 如果我绝对不得不以我提问的方式照顾我的问题,那就是对的。但是我最终所做的是通过在B上添加一个“RunAsync”布尔字段来强制任务同步运行,如果(!RunAsync){task.wait();)加上 。 } 里面的RaiseAsyncEvent,并设置b.RunAsync = false;在TestInitialize中。不是最漂亮的,但它是一个简单的修复,可能是一个非常复杂的问题。 –
如果您想避免更改构造函数签名,请考虑由所有事件共享的TaskScheduler(单例)的静态实例。然后,不要在所有对象上设置RunAsync属性,而只需将ConcurrentScheduler分配给静态属性。 – alexm
我正在使用的代码比我在这里展示的要复杂得多 - 我实际上实现了我自己的静态CallbackManager,它将事件传入并生成一个新的任务,这个任务根据几个因素运行异步或同步,保存句柄,并处理返回逻辑。我添加的布尔允许我绕过异步逻辑并强制它从一开始就同步,这样我的所有单元测试仍然可以通过。由于管理器是静态的,因此在测试开始时,不需要对RunAsync bool进行一次更改,而且它可以正常运行。 –