Saturday, April 12, 2014

Verify event was raised with NSubstitute

I used to unit-test events by subscribing to them with my custom handler which job was to set a flag when the event was called and remember its parameters (if existed). At the end I used assertions to verify if the event was raised and if so whether the parameters were correct.

The behavior I'm going to test is that OfficeDevice should raise Alarm when someone wants to print any document when there is no ink in the device. This is how my tests looked like.

[Test]
public void ShouldAnnounceWhenPrintingWithNoInk()
{
  //GIVEN
  var device = new OfficeDevice(ink: 0);
  InkLevel? level = null;
  device.InkAlarm += (levelParameter) => { level = levelParameter; };

  //WHEN
  device.Print(Any<IDocument>());

  //THEN
  Assert.AreEqual(InkLevel.None, level);
}

This is actually similar to what NSubstitute documentation encourages to do. There's nothing wrong with this. However, a colleague showed me another way of testing events with the spy and verify tactics.

[Test]
public void ShouldAnnounceWhenPrintingWithNoInk()
{
  //GIVEN
  var device = new OfficeDevice(ink: 0);
  var subscriber = Substitute.For<IDummySubscriber>();
  device.InkAlarm += subscriber.React;

  //WHEN
  device.Print(Any<IDocument>());

  //THEN
  subscriber.Received(1).React(InkLevel.None);
}

IDummySubscriber is just a dummy interface for mocking purpose.

public interface IDummySubscriber
{
  void React(InkLevel level);
}


I like the second approach because it's much neater. You can to get rid of flags and lambdas and replace them with mock verification.

1 comment: