【发布时间】:2017-04-22 17:22:52
【问题描述】:
您好,我在使用 NUnit 测试事件时遇到问题。我什至不确定这应该是单元测试还是功能测试。让我先给你看示例类(我正在尝试测试OnValueInjected 事件):
public class Foo
{
private IBar CurrentBar { get; set; }
public event EventHandler<MoveEventArgs> OnValueInjected;
public Foo()
{
StartFoo();
}
private async void StartFoo()
{
await Task.Factory.StartNew(() =>
{
while (State != FooState.Finished)
{
IResult result = CurrentBar.WaitForValue(); // This is blocking function, wait for a value
OnValueInjected?.Invoke(this, new ResultEventArgs(result));
// .. rest of the loop
}
});
}
public void InjectValue(int a, int b)
{
CurrentBar.Inject(a,b);
}
}
所以,基本上我要做的是订阅该事件,调用InjectValue 并检查是否调用了该事件。像这样:
[Test]
public void FooOnValueInjectedTest()
{
bool OnValueInjectedWasRasied = false;
IFoo foo = new Foo();
foo.OnValueInjected += (s, e) => OnValueInjectedWasRasied = true;
foo.InjectValue(0,0);
Assert.AreEqual(true, OnValueInjectedWasRasied);
}
非常简单,但看起来InjectValue 太慢了。测试失败了..我认为它太慢了,因为当我在 InjectValue 和 Assert 之间添加 Thread.Sleep 时。
foo.InjectValue(0,0);
Thread.Sleep(1000);
Assert.AreEqual(true, OnValueInjectedWasRasied);
有没有更好的方法来测试这样的事件?谢谢
我修好了我的课,所以现在是这样的:
public class Foo
{
private AutoResetEvent AutoReset { get; }
private IBar CurrentBar { get; set; }
public event EventHandler<MoveEventArgs> OnValueInjected;
public Foo()
{
AutoReset = new AutoResetEvent(false);
StartFoo();
}
private async void StartFoo()
{
await Task.Factory.StartNew(() =>
{
while (State != FooState.Finished)
{
IResult result = CurrentBar.WaitForValue(); // This is blocking function, wait for a value
OnValueInjected?.Invoke(this, new ResultEventArgs(result));
AutoReset.Set();
// .. rest of the loop
}
});
}
public void InjectValue(int a, int b)
{
if (CurrentBar.Inject(a,b))
{
AutoReset.WaitOne();
}
}
}
【问题讨论】:
-
那么,您是否想要在事件处理程序确定被引发之前返回您的
InjectValue?您基本上看到了异步的自然结果……这实际上与事件无关,而是与异步执行有关。 -
@JonSkeet hmm.. 从技术上讲,您是说
InjectValue可以被阻止直到OnValueInjected被提出?其实我还没想好.. -
如果你想要这种行为,你可以确保它,是的。但不管你是否这样做是另一回事。
-
@JonSkeet 谢谢!我实际上想要这种行为。我用更新的代码编辑了我的问题。你能检查一下这是否是你的意思吗?测试通过了,但我只是想确保我们在同一页面上,谢谢!
-
这是一种潜在的解决方案,但您可能需要考虑多个线程同时调用
InjectValue的情况。如果您想确保对InjectValue的一次调用仅在 那个 值触发所有事件处理程序时完成,这将非常棘手。哦,如果事件处理程序自己调用InjectValue,它也会死锁。很抱歉指出这些问题 - 线程本身就很难:(
标签: c# .net unit-testing testing nunit