我倾向于转向只考虑公共接口的观点,从而涵盖私人程序的测试。然而,昨天出现了一个有趣的问题 - 应该测试事件处理程序吗?我的直觉是逻辑应该存储在由处理程序自己调用的自包含程序中,但这是主观的,并且很可能导致私有程序而不是正在测试的公共程序。我是否应该对事件处理程序进行单元测试?如果是,那么这样做的最佳做法是什么?
答案 0 :(得分:2)
对于单元测试事件处理程序,我绝不会说某人“错误”。就个人而言,我会选择“测试可能会破坏”的理念而不会。
我看到的事件代码一直出错的主要原因是单元测试无法捕获 - “On”方法只是:
if (MyEventHandler != null)
MyEventHandler(this, e);
这有竞争条件;应在空检查之前将MyEventHandler分配给变量。
第二个常见错误是为“e”事件数据参数传递null的人;这可以测试。
如果您没有第2版框架设计指南的副本。通过Cwalina&艾布拉姆斯,现在买。它将告诉您如何每次正确编写事件代码,如何正确编写Dispose模式以及许多其他内容。
答案 1 :(得分:0)
我认为应该测试事件处理程序。如果你遵循以下方式做某事的正常模式:
public event EventHandler MyEvent;
protected void OnMyEvent()
{
// Raise MyEvent here
}
然后测试MyEvent实际上是OnMyEvent测试的一部分,因为你要做的唯一“测试”是验证事件是否正确引发。
通常情况下,测试一个事件意味着订阅它,并做一些应该(或不应该)提出它的事情。
答案 2 :(得分:0)
我读了你的问题,并且不知道你是否在询问处理程序的主体,或者处理程序是否实际上已经正确绑定以处理事件。
正如你所说,处理程序的主体应该只调用另一个你已经测试过的方法(如果是公共的)。
我通常不会对事件处理程序的连接进行单元测试,除非它们在运行时会发生变化,因为我很可能会遇到我的开发人员和集成测试事件处理程序,它们不会绑定/取消绑定运行时,没有接线,应该是。
答案 3 :(得分:0)
至于TrueWill的观点,这里是一个很好的事件实现及其raise方法的例子。这是Microsoft的Click
类的Button
事件。首先请注意,他们使用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();
}