简体   繁体   English

单元测试在事件触发时在类上执行void方法

[英]Unit test that a void method on a class is executed when an event fires

Suppose you had 2 classes, Listener and Talker. 假设您有两个类,即Listener和Talker。 Talker has an event Talking, and when this event is fired, Listener should execute a void method HeardTalk, along these lines: Talker有一个Talking事件,当触发该事件时,Listener应该按照以下方式执行一个无效方法HeardTalk:

public class Talker
{
   public event EventHandler Talking;

   public void Talk()
   {
      if (Talking != null)
      {
         Talking(this, null);
      }
   }
}

public class Listener
{
   public void StartListening(Talker talker)
   {
      talker.Talking += HeardTalk;
   }

   public void HeardTalk(object sender, EventArgs e)
   {
      // do something private here
   }
}

How would you go about unit testing that once StartListening has been called, HeardTalk gets called, if there was no public state reflecting that the method was called? 如果没有公共状态反映该方法已被调用,则如何进行单元测试,一旦调用StartListening并调用HeardTalk,该如何进行? I could just add such a state for the purpose of validation, but it seems clumsy. 我可以添加这样的状态以进行验证,但是看起来很笨拙。 Ideally, I would like to assert the call was made, in a manner similar to what Mocking frameworks do, but I can't mock the class under test. 理想情况下,我想断言调用是通过类似于Mocking框架的方式进行的,但是我无法模拟正在测试的类。

Is there an elegant way to assert that a method was called on the SUT, without modifying it just for the purpose of testability? 有没有一种优雅的方法可以断言在SUT上调用了一种方法,而没有仅仅出于可测试性的目的对其进行修改?

There must be at least some measurable side effect from the event being triggered. 触发事件至少必须有一些可测量的副作用。 Perhaps you are logging the event, saving something to a data-store, or changing the internal state of your class. 也许您正在记录事件,将某些内容保存到数据存储中或更改类的内部状态。

If you are calling to any external dependencies those should be passed in via constructor/property injection and mocked. 如果您要调用任何外部依赖项,则应通过构造函数/属性注入将它们传递并进行模拟。 In the case of changing internal state then even doing that must have some side effect that can be observed externally. 在改变内部状态的情况下,即使这样做也必须具有一些可以从外部观察到的副作用。 Otherwise what would be the point? 否则,重点是什么?

In the end if all you want to check is that the method got called, then what are you actually testing? 最后,如果您只想检查方法是否已被调用,那么您实际要测试什么? Again, there must be a reason that method gets called, and that reason has to have some impact that can be observed somewhere... 同样,必须有一个方法被调用的原因,并且该原因必须具有某些可以在某处观察到的影响...

You can do such things easily with the commercial Typemock Isolator , which allows you to selectively 'mock' individual methods on 'real' objects. 您可以使用商业化的Typemock隔离器轻松地执行此类操作,该隔离器使您可以有选择地在“真实”对象上“模拟”单个方法。
The test would look like this: 测试看起来像这样:

[Test, Isolated]
public void HeardTalk_GetsCalled()
{
    // --- Arrange ---
    var talker = new Talker();
    var listener = new Listener();
    bool heardTalkWasCalled = false;
    Isolate.WhenCalled(() => listener.HeardTalk(null, null))                     // Selectively 'mock' the call to 'listener.HeardTalk()'
                                     .DoInstead(x => heardTalkWasCalled = true); // on the live object (arguments are ignored by default)

    // --- Act ---
    listener.StartListening(talker);
    talker.Talk();

    // --- Assert ---
    Assert.IsTrue(heardTalkWasCalled);
}

Admittedly, Typemock Isolator comes with some license costs. 诚然,Typemock隔离器带有一些许可费用。 But if you're serious about testing and need to test a lot of stuff like the above, it's worth every penny because of its strength and flexibility. 但是,如果您认真对待测试,并且需要测试很多类似以上的内容,那么它的强度和灵活性就值得每一分钱。

Notes: 笔记:

  • You can do the same with the free MS Moles framework (for Visual Studio 2010), which is a suitable alternative to Typemock, if you have to do such tests only occasionally. 如果仅偶尔需要进行此类测试,则可以使用免费的MS Moles框架 (适用于Visual Studio 2010)执行相同的操作,该框架可以替代Typemock。 It generally requires somewhat more work/code, adds more complexity to the tests, and is more performance-demanding especially during compilation, but is sufficient for smaller test suites. 它通常需要更多的工作/代码,给测试增加更多的复杂性,并且对性能的要求更高,尤其是在编译过程中,但对于较小的测试套件而言已足够。
  • There is also a commercial alternative from Telerik called JustMock . Telerik还有一个商业替代品JustMock Because it is quite new, I can't say nothing about it except that it exists... 因为它是一个很新的东西,所以除了它存在之外我无话可说...

HTH! HTH!
Thomas 托马斯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM