【问题标题】:Unit-testing event-triggered behaviour单元测试事件触发的行为
【发布时间】:2011-02-25 09:09:22
【问题描述】:

我使用模式已经有一段时间了。我想知道我是否做对了。我有一个监听事件的控制器类,并在引发事件时执行一个私有方法。它有点像这样:

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 方法保持私有,以说明只有事件才能触发它。另一方面,私有方法包含关键业务逻辑,所以我觉得它应该是公共的,或者至少是内部的,这也将使单元测试更容易。

你们怎么看?

问候, 莫腾

【问题讨论】:

  • 为什么不像其他私有方法一样使用私有访问器(即反射)来测试您的私有方法?
  • 这对我来说是一个未知的程序。一定会查的:-)
  • 你的所作所为没有什么不妥之处。不过有一条评论:您可能需要 mock,甚至是 fake,但不需要 stub。通常,存根不会做任何事情,也不会触发任何事件。

标签: c# unit-testing tdd nunit


【解决方案1】:

你所得到的听起来像是(轻度)违反SRP。您的控制器既响应事件又保存为特定事件执行的复杂逻辑。如果您的控制器只是将必要的数据发送到执行实际工作的专用处理器怎么办?该处理器的方法必然是公开的——因此是可测试的! TDD 指出 SRP 违规的方式不是很好吗?

【讨论】:

  • 啊,你说我既是控制又是调解?我应该考虑将两者分开,控制部分——我现在在私有方法中执行——应该在它自己的类中?
  • 可能是这样。我是说值得考虑拆分。
  • 如果事件处理器负责改变Controller本身的状态呢?例如公共属性的一些返回值。那么模拟一个事件触发器并“测试内部”就可以了吗?还是应该寻找更好的选择?
【解决方案2】:

您是否研究过模拟框架? "Moq" 支持从模拟类型引发事件:

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

【讨论】:

  • 是的,这就是我所做的。但是,您一般如何看待这种模式? :-)
  • @Morten 我通常不喜欢依赖事件来触发,但您的实现看起来还不错,而且完全合法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 2010-12-26
  • 1970-01-01
  • 2011-05-06
  • 2015-04-17
相关资源
最近更新 更多