2012-03-22 74 views
4

我有一个具有公共方法Start,一个私有方法和一个事件Finishing类。 Start致电new Thread(private_method)。使用事件的私有方法返回值。当这个方法完成他们的工作,然后调用这个事件。测试方法(NUnit的2.6)

现在我想写测试此类。如果我这样写:

[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在事件发生之前完成。那么,我该如何测试这些代码呢?如何测试方法,它创建一个新的线程,并导致我们从事件

回答

16

NUnit有内置的功能来等待断言。这就是所谓的 '后':

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

不知道,我使用FluentAssertions而不是内置的NUnit断言。刚刚检查出来,他们有一些事件监测断言。 http://fluentassertions.codeplex.com/documentation – Bronumski 2012-03-22 23:22:56

+0

内置等待相当不错。它允许定义超时和轮询间隔Is.EqualTo(“完成”)。(500,50)之后。所以你不需要等很长时间,如果事情发生很快:) – 2012-03-22 23:26:17

+0

这个解决方案看起来很不错,但..我有这个问题。我不确定发生了什么。在我的例子中'eventRaised'被正确设置为'true'(我把它写在控制台上)。但是'断言。(事件发生了,Is.True.After(5000))';' “告诉我”'eventRaised'是'false' ..怎么可能?我不确定,但也许它是'bool'的问题,它不是引用类,所以也许'Assert.That()'获得这个'eventRaised'就像false,并且它不引用'eventRaised'我在'event'设置为'true' .. – nirmus 2012-03-23 01:31:06

1

你是对的获得。

首先,NUnit的和它的各种主机环境已经或者还有,各种缺陷和限制线程测试中开始。尤其是,如果在测试执行完成之前不确定线程​​是否完成,那么NUnit不知道有人正在执行代码,在测试返回后它将卸载。我经常记住这种模式,当通过Resharper集成来执行NUnit时,会定期导致VS崩溃,以及偶尔出现的与NUnit一起提供的GUI和控制台运行程序的故障和内存泄漏。

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

  1. 通过连接所产生的所有线程来实现测试环境的基本安全。
  2. 仅在主线程中抛出指示测试失败的所有异常。这意味着后台线程必须将其结果传递给主线程,并且该线程必须完成所有各种不变量。

更好的是,构造您的代码,以便您可以在没有后台线程的情况下进行单元测试 - 如果可能的话。

+0

感谢解释。我以为我的老师告诉我使用NUnit,因为它是非常好的框架..我错了;) – nirmus 2012-03-22 22:49:41

+0

@nirmus - 不,NUnit绝对好!但* unit *测试背后的想法是,您理想地测试非常小的代码块(单位)。大集成测试也是可能的,但它必须是独立的。如果你做出了一些动作,你也应该在测试中停下来,这样它就是自成一体的。 NUnit不知道你做了什么。 – 2012-03-22 23:00:48

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属性你可以装饰测试用。

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

这应该工作