C# 如何在单元测试时捕获事件?
您好,我在使用C# 如何在单元测试时捕获事件?,c#,.net,unit-testing,testing,nunit,C#,.net,Unit Testing,Testing,Nunit,您好,我在使用NUnit测试事件时遇到问题。我甚至不确定这是单元测试还是功能测试。让我首先向您展示示例类(我正在尝试测试OnValueInjectedevent): 非常简单,但是看起来InjectValue太慢了。测试失败了..我认为它太慢了,因为当我添加线程时,InjectValue和Assert之间的Sleep起作用 foo.InjectValue(0,0); Thread.Sleep(1000); Assert.AreEqual(true,
NUnit
测试事件时遇到问题。我甚至不确定这是单元测试还是功能测试。让我首先向您展示示例类(我正在尝试测试OnValueInjected
event):
非常简单,但是看起来InjectValue
太慢了。测试失败了..我认为它太慢了,因为当我添加线程时,InjectValue
和Assert
之间的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();
}
}
}
公共类Foo
{
私有自动重置事件自动重置{get;}
专用IBar CurrentBar{get;set;}
公共事件事件处理程序OnValueInjected;
公共食物(
{
自动重置=新自动重置事件(假);
StartFoo();
}
私有异步void StartFoo()
{
等待任务。工厂。开始新建(()=>
{
while(State!=FooState.Finished)
{
IResult result=CurrentBar.WaitForValue();//这是阻塞函数,请等待值
OnValueInjected?.Invoke(这个,新的结果ventargs(结果));
AutoReset.Set();
//…循环的其余部分
}
});
}
公共值(整数a、整数b)
{
if(电流条注入(a,b))
{
AutoReset.WaitOne();
}
}
}
我认为这是异步调用的问题。无论何时在NUnit测试中有一个异步方法,它都不会等待它完成,因为实际上没有人在等待它完成并返回结果。相反,您必须对async方法执行.Wait,以强制测试等待完成
我没有在代码编辑器中编写此代码,因此它可能并不完美,但这是基本思想
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 async void InjectValue(int a, int b)
{
if (CurrentBar.Inject(a,b))
{
AutoReset.WaitOne();
}
}
}
那么,您是否希望在事件处理程序确实被引发之前返回
InjectValue
?您基本上看到了异步的自然结果。。。它实际上不是关于事件,而是关于异步执行。@JonSkeet-hmm。。从技术上讲,您是说,InjectValue
可以被阻止,直到引发OnValueInjected
?其实我还没想过……如果你想要那种行为,你可以保证,是的。不管你做不做都是另外一回事。@JonSkeet谢谢!我真的想要那种行为。我用更新的代码编辑了我的问题。你能看看这是不是你的意思吗?测试通过了,但我只是想确定我们在同一页上,谢谢!这是一个可能的解决方案,但是您可能需要考虑多线程同时调用<代码>注入值< /代码>的情况。如果您想确保只有当InjectValue
的一个调用触发了所有事件处理程序时,才能完成该调用,那么这将非常棘手。哦,如果事件处理程序调用InjectValue
本身,它也会死锁。很抱歉指出这些问题-线程本来就很难:(谢谢你的建议,但是foo.InjectValue(0,0);
函数是不可等待的。不必等待。它应该向阻塞集合中注入一个值。在集合被填充后,它就被释放了。这是一个非常真实的场景-所以我想知道如何测试它(没有更改ofc的代码)。我应该测试它吗?我一定误解了该方法,认为Inject方法正在调用其中的另一个异步方法。我的错。至于你应该测试它吗?这取决于“你想测试什么?”这一问题的答案似乎没有太多需要测试的地方。
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();
}
}
}
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 async void InjectValue(int a, int b)
{
if (CurrentBar.Inject(a,b))
{
AutoReset.WaitOne();
}
}
}
[Test]
public void FooOnValueInjectedTest()
{
// Arrange
bool OnValueInjectedWasRasied = false;
IFoo foo = new Foo();
foo.OnValueInjected += (s, e) => OnValueInjectedWasRasied = true;
// Act
foo.InjectValue(0,0).Wait();
// Assert
Assert.AreEqual(true, OnValueInjectedWasRasied);
}