2017-04-22 48 views
0

嗨我有一个问题,使用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太慢。测试失败..我认为这太慢了,因为当我在InjectValueAssert之间添加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(); 
     } 
    } 
} 
+2

那么,你想* *您'InjectValue'返回的事件处理程序肯定有人提出过吗?你基本上看到了异步的自然结果......它不是关于事件,而是关于异步执行。 –

+0

@JonSkeet嗯..从技术上讲,你是说'InjectValue'可以被阻止,直到'OnValueInjected'被提出?我没有想到这个实际上.. –

+0

如果你想*的行为,你可以确保它,是的。不管你是否做了不同的事情。 –

回答

0

我相信这是异步调用的问题。只要你在NUnit测试中有一个异步方法,它就不会等待它完成,因为没有人真的在等待它完成并返回结果。相反,你必须做一个。等待异步方法来强制测试等待它完成。

我没有在代码编辑器中编写代码,所以它可能不完美,但这是基本思想。

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(); 
     } 
    } 
} 
在ACT测试方法

那么你是一个.Wait

[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); 
} 
+0

感谢您的建议,但'foo.InjectValue(0,0);'功能不能等待。不一定是。它应该为阻塞收集注入一个值。收集完成后,它被释放。这是一个非常真实的场景 - 所以我想知道如何测试它(不改变c的代码)。我应该测试它吗? –

+0

我一定误解了这个方法,并认为Inject方法正在调用另一个异步方法。我的错。 至于你应该测试它?这取决于“你想测试什么?”这个问题的答案。在那里测试似乎并不多。 – AzzamAziz