单元测试时如何捕捉事件?

时间:2017-04-22 17:22:52

标签: c# .net unit-testing testing nunit

您好我在使用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太慢了。测试失败了。我认为它太慢了,因为当我在Thread.SleepInjectValue之间添加Assert来工作时。

        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();
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我认为这是异步调用的问题。每当你在NUnit测试中有一个异步方法时,它就不会等待它完成,因为没有人真正等待它完成并返回结果。相反,您必须对异步方法执行.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();
        }
    }
}

然后在你在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);
}