测试方法创建一个新的线程和我们从事件得到的结果(NUnit 2.6)

时间:2012-03-22 22:28:54

标签: c# unit-testing nunit

我的课程有一个公共方法Start,一个私有方法和一个事件FinishingStart致电new Thread( private_method )。私有方法使用事件返回值。当此方法完成其工作时,请调用此事件。

现在我想给这个班写测试。如果我这样写:

    [Test]
    public void Test1()
    {
        SomeClass someObject = new SomeClass();

        someObject.Finishing += new SomeClass.FinishingEventHandler((sender, a) =>
        {
            Assert.True(false);
        });
        someObject.Start(); // when this method will finish, then call event Finishing
    }

应该失败,但事实并非如此。我认为方法Test1在事件发生之前完成。那么,我该如何测试这段代码呢?如何测试方法,创建新线程,以及我们从事件

获得的结果

4 个答案:

答案 0 :(得分:16)

NUnit具有等待断言的内置功能。它被称为'After':

[Test]
public void ShouldRaiseFinishedEvent()
{
    SomeClass someObject = new SomeClass();
    bool eventRaised = false;
    someObject.SomethingFinished += (o, e) => { eventRaised = true; };

    someObject.DoSomething();
    Assert.That(eventRaised, Is.True.After(500));
}

答案 1 :(得分:2)

[Test]
public void ShouldRaiseFinishedEvent()
{
    SomeClass someObject = new SomeClass();
    AutoResetEvent eventRaised = new AutoResetEvent(false);
    someObject.SomethingFinished += (o, e) => { eventRaised.Set(); };

    someObject.DoSomething();
    Assert.IsTrue(eventRaised.WaitOne(TimeSpan.FromMilliseconds(500)));
}

这应该有效

答案 2 :(得分:1)

你是对的。

首先,NUnit及其各种托管环境在测试中启动的线程之间已经或者仍然存在各种缺陷和限制。特别是,如果在测试执行完成之前没有确保线程完成,那么NUnit不知道有人在代码中执行它将在测试返回后卸载它。我记得当NUnit通过Resharper集成从它执行时,这个模式经常导致VS崩溃,以及随NUnit提供的GUI和控制台运行程序的偶尔故障和内存泄漏。

那就是说,你需要确保两件事。

  1. 通过连接您生成的所有线程来确保测试环境的基本安全。
  2. 仅抛出指示主线程上的测试失败的所有异常。这意味着后台线程必须将其结果传递给主线程,并且必须Assert所有各种不变量。
  3. 更好的是,构建代码,以便在没有后台线程的情况下对其进行单元测试 - 如果可能的话。

答案 3 :(得分:0)

如前所述,您可以对多线程组件进行单元测试,但它不像常规单元测试那样干净。我在接受测试中大多遇到过它,并且在.net 4 TaskParallel类中取得了很大的成功。但是在这种情况下,一个简单的睡眠可能会让你开始,但如果你开始做很多这些测试,你可能需要一种更高效的方法。

[Test]
public void Test1()
{
    bool wasCalled = false;

    SomeClass someObject = new SomeClass();

    someObject.Finishing += new SomeClass.FinishingEventHandler((sender, a) =>
    {
        wasCalled = true;
    });
    someObject.Start(); // when this method will finish, then call event Finishing

    Thread.Sleep(2000);

    Assert.True(wasCalled);
}

你做了什么,你需要一些超时,导致测试完成而不是永远悬挂,这可以在测试本身完成,或者一些测试库有一个Timeout属性你可以装饰测试