单元测试事件触发行为

3

我已经使用了一种模式有一段时间,但我想知道我是否做得正确。我有一个控制器类监听事件并在事件被触发时执行一个私有方法。它的实现大概是这样的:

public class MyController
{

    public MyController(IMyEventRaiser eventRaisingObject)
    {
        eventRaisingObject.MyEvent += HandleEvent;
    }

    private void HandleEvent(object sender, EventArgs args)
    {
        // SOME STUFF I WANT TO TEST!!
    }
}


public class EventRaisingClass : IMyEventRaiser
{
    public event EventHandler<EventArgs> MyEvent;
}

测试MyController.HandleEvent方法的唯一方式是创建一个stub:IMyEventRaiser来触发代码。

我不确定这种设计是否合适。一方面,我想将HandleEvent方法保持为private,以说明只有事件才能触发它。另一方面,如果私有方法包含关键业务逻辑,那么我觉得它应该是public,或者至少是internal,这也会使单元测试变得更加容易。

你们觉得呢?

谢谢,Morten


为什么不使用私有访问器(即反射)来测试您的私有方法,就像测试其他私有方法一样呢? - Massif
这个过程对我来说是未知的。一定会去查一下 :-) - Morten
1
你所做的事情没有任何不妥之处。但有一个注释:你可能需要一个“模拟对象”(mock),或甚至是一个“仿造对象”(fake),而不是一个“存根”(stub)。通常,存根无法触发任何事件并且没有实际效果。 - Ates Goral
2个回答

6
你所描述的情况似乎是SRP(单一职责原则)的轻微违反。你的控制器既响应事件又包含在特定事件下执行的复杂逻辑。如果你的控制器将必要的数据简单地分派到专用处理器进行实际操作,会怎样呢?该处理器的方法必然是公开可访问的,因此可以进行测试!TDD(测试驱动开发)不正是揭示SRP违规的好方法吗?

1
啊,你的意思是说我既要控制又要调解?而且我应该考虑将这两个方面分开,把现在我执行的控制部分放到一个独立的类中? - Morten
可能是这样。我认为值得考虑分裂。 - Carl Manaster
如果事件处理程序负责更改控制器本身的状态,例如公共属性的某些返回值。那么模拟事件触发并“测试内部”是否可以?还是应该寻找更好的替代方案? - joe

2

您是否了解模拟框架?"Moq"支持从模拟类型中触发事件:

Mock<IMyEventRaiser> mock = new Mock<IMyEventRaiser>()
mock.Raise(e => e.MyEvent, EventArgs.Empty);

是的,这就是我所做的。但你对这个模式有什么看法? :-) - Morten
@Morten 我通常不喜欢依赖于事件的触发,但是你的实现看起来很好,完全合法。 - J. Tihon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接