2009-08-27 96 views
4

我倾向于认为只有公共接口应该被测试,因此涵盖私人程序的测试。然而,昨天出现了一个有趣的问题 - 应该测试一个事件处理程序吗?我的直觉是,逻辑应该存储在由处理程序自己调用的独立程序中,但这是主观的,并且很可能导致私有程序而不是正在测试的公共程序。我应该成为单元测试事件处理程序吗?如果是,那么这样做的最佳实践是什么?我应该单元测试事件处理程序

回答

0

我相信应该测试事件处理程序。如果你遵循的线沿线的做一些事情的正常模式:

public event EventHandler MyEvent; 
protected void OnMyEvent() 
{ 
    // Raise MyEvent here 
} 

然后MyEvent的测试实际上是OnMyEvent的测试的一部分,因为只有“测试”,你会做的是验证事件适当提升。

通常情况下,测试一个事件意味着订阅它,并做一些应该(或不应该)提高它的事情。

0

我看了你的问题,并不知道你是在询问处理程序的主体还是处理程序是否实际绑定正确来处理事件。

正如你所说,处理程序的主体应该简单地调用另一个已经测试过的方法(如果它是公开的)。

我通常不会单元测试事件处理程序的接线,除非它们在运行时会发生变化,因为我很可能会捕捉到我的开发人员和集成测试事件处理程序不绑定/解除绑定在运行时,没有连接,应该是。

2

我决不会说某人对单元测试事件处理程序是“错误的”。就我个人而言,我会遵循“测试可能会破坏”的理念,而不会。

我见过的一贯毛病事件代码的主要是一些单元测试不会赶上 - “开”的方法将只是:

if (MyEventHandler != null) 
    MyEventHandler(this, e); 

这有一个竞争条件; MyEventHandler应该在空检查之前分配给一个变量。

第二个常见错误是人们为“e”事件数据参数传递null;这可以进行测试。

如果您没有自己的Framework Design Guidelines 2nd Ed。 Cwalina & Abrams,现在购买。它会告诉你如何正确地编写事件代码,如何正确编写Dispose模式,以及其他许多事情。

+0

那真的去了我想你说的话这么我发布了一些希望能够与您所说的内容互补的内容,非常适合将此称为朋友,非常好! – 2012-10-05 13:06:36

0

为了TrueWill的观点,下面是一个很好的实现事件及其提升方法的例子。这是Microsoft的Button类的Click事件。首先要注意他们使用EventHandlerList的分配存储在...

protected EventHandlerList Events { 
    get { 
     if (events == null) { 
      events = new EventHandlerList(this); 
     } 
     return events; 
    } 
} 

... 

public event EventHandler Click { 
    add { 
     Events.AddHandler(EventClick, value); 
    } 
    remove { 
     Events.RemoveHandler(EventClick, value); 
    } 
} 

现在注意到的实际加薪方法OnClick,它可能比你在做什么看惯了太多不同的...

protected virtual void OnClick(EventArgs e) { 
    Contract.Requires(e != null); 
    EventHandler handler = (EventHandler)Events[EventClick]; 
    if (handler != null) handler(this, e); 
} 

...不要担心线路Contract.Requires(e != null);,这是他们的合同管理框架,但是请注意,它将它从EventHandlerList中拉出来,然后如果该处理程序不是null,它们将会触发它。

这里可能值得注意的另一件事是,你可能不需要以完全相同的方式实现你的事件,但是微软推出的编程指南实际上在这个第二部分中调用了竞争条件TrueWill指出的指南。你可以找到该指南here。这实际上是微软的一个很好的指导。

现在,要贵点,我认为事件应进行测试,这里是我在过去使用的机制......

private ManualResetEvent _eventRaised = new ManualResetEvent(false); 

[TestMethod] 
public void TestSomething() 
{ 
    _eventRaised.Reset(); 

    // hook up the event to the target being tested 
    // NOW, in the event handler, issue _eventRaised.Set(); 

    // do something to raise the event 

    _eventRaised.WaitOne(); 
} 
相关问题