【问题标题】:Verifying event handler code executed验证执行的事件处理程序代码
【发布时间】:2012-02-20 13:36:45
【问题描述】:

我的代码与此非常相似,但无法确定如何测试事件处理程序是否发生。

public class MyClass : MyAbstractClass
{ 
  IFileSystem FileSystem;

  public MyClass(IFileSystem myFileSys)
  {
    FileSystem = myFileSys;
    FileSystem.EventHit += new EventHandler(FileSystem_EventHit);
  }

  public void FileSystem_EventHit(object sender, EventArgs e)
  {
    //Testing base.OnOutput is not possible which I wont go into
    base.OnOutput("EventHit");
  }
}

测试代码在这里:

    [Test]
    public void DoSomething_WhenCalled_EventFired()
    {
         var mock = new Moq.Mock<IFileSystem>();

         MyClass plugin = new MyClass (mock.Object);

         mock.Object.DoSomething();

         mock.Raise(x => x.EventHit += null, new EventArgs());

        //Verify/Assert that MyClass handled and did something in the event handler

    }

【问题讨论】:

  • 能否详细介绍一下WRT base.OnOutput,或许可以测试?
  • MyAbstractClass 是遗留的,MyClass 也是如此,因此它很混乱,需要大量设置来测试,所以我希望有一些方法可以测试而无需验证 base.OnOutput
  • 常见场景;回顾性地编写单元测试。我不知道有什么捷径。每当我遇到这个问题时,我都会发现自己正在重构代码以便对其进行单元测试。
  • @MylesMcDonnell 希望我有这个选项 :)
  • 听起来很难看,所以你必须编写单元测试而不使代码可测试,哎哟。一种不完美但实用的方法是接受某些类型是紧密耦合的,并围绕这些类型定义测试边界。不是严格意义上的单元测试,但在启用测试时可能对您有一些价值?

标签: c# .net unit-testing .net-4.0 tdd


【解决方案1】:

我能想到的最简单的方法就是在测试方法中添加你自己的处理程序,我认为这应该足够了吗?

[Test]
    public void DoSomething_WhenCalled_EventFired()
    {
         var mock = new Moq.Mock<IFileSystem>();
         bool isHit = false;

         mock.EventHit += (s, e) =>
         {
            isHit = true;
         };

         MyClass plugin = new MyClass (mock.Object);

         mock.Object.DoSomething();

         mock.Raise(x => x.EventHit += null, new EventArgs());

         Assert.IsTrue(isHit);

    }

【讨论】:

  • 这将断言模拟引发了事件,它不会确认 MyClass.FileSystem_EventHit 被调用或验证结果发生了什么。
【解决方案2】:

由于在事件处理程序中验证某些内容意味着尝试测试遗留代码,所以我选择的选项是测试事件是从具体类型中触发的,而不是从模拟中触发的。

[Test]
public void DoSomething_WhenCalled_EventFired()
{

  FileSystem fs = new FileSystem(mock.Object, timerMock.Object);

  bool WasItHit = false;
  fs.EventHit += delegate { WasItHit = true; };

  fs.DoSomething(); //This should call the event

  Assert.IsTrue(WasItHit);
}

【讨论】:

    【解决方案3】:

    您需要注入由于事件处理程序调用而被调用的任何内容的模拟并验证它。您的评论说您无法测试基本 base.OnOutput,但在我看来这正是您需要做的。

    【讨论】:

    • 这就是问题所在!抽象类,主要是 MyClass 是遗留代码,它是测试的噩梦
    【解决方案4】:

    基本上测试方法被调用的事实不是有效的测试用例,您应该测试方法背后的逻辑/行为。显然,对于给定的事件处理程序,没有什么要测试的,这就是为什么任务看起来不简单的原因。

    试着用几句话来表述你要测试什么,哪个测试用例。比如

    MyClass 将状态切换到 State==Hit 同时 FileSystem.EventHit 事件。

    【讨论】:

    • 我同意,但 MyClass 充当输入/输出类型的类,因此调用 DoSomething 的某些东西会触发事件并执行输出
    • 它对 Jon 做了什么输出?如果它是另一个依赖项,则模拟 MyClass 或基类用于执行输出的依赖项,并验证是否使用该依赖项对输出进行了调用。
    • 是的,我会这样做,但它所有的旧代码都是设置的噩梦
    • @Jon :对,为遗留代码编写单元测试也是一场噩梦
    【解决方案5】:

    为此,您可能需要在 MyClass 中设置一个标志来指示该事件已发生。我知道,这只是为了运行测试,但有时有这样的东西很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-27
      • 1970-01-01
      相关资源
      最近更新 更多