Damian Stanger Damian Stanger - 11 months ago 52
C# Question

Using NserviceBus.Testing how do you test the published event when the code is not initiated via a message handler


If the current method being tested is initiated via some other method than an incoming message (into a handler) how do you test the publishing of events. The problem with NServiceBus.Testing (as far as I see it) is that its very geared towards testing handlers which in turn cause messages/events to be send/published.


We have a number of legacy systems, and in the ongoing effort to move to a proper SOA implementation we need to integrate with some legacy DB jobs. These jobs perform actions on the DB every 15 minutes which we want to hook into and publish events when certain conditions occur.

We have a windows service that is running within the NsbHost but that contains no handlers. Instead we are using Quartz to create an internal cron job that runs every minute, polls the DB for records that match a specified pattern, and publishes an event before updating the DB to say we have processed that record. This is how we are integrating old and new systems.

Clearly this is not an ideal situation but given that we are in a transition phase in our SOA implementation its as good as we have right now.

Details and code:

Our event interface we are publishing looks like this

public interface IPremiumAdjustmentFinalised
string PolicyNumber { get; set; }
decimal Amount { get; set; }
DateTime FinalisedOn { get; set; }

The code to actually publish the event is

Bus.Publish<IPremiumAdjustmentFinalised>(e =>
e.Amount = AdjustmentAmount;
e.PolicyNumber = PolicyNumber;
e.FinalisedOn = LastModifiedOn;

This all works fine and we can test the call was made using MOQ thus:

bus.Verify(x => x.Publish(It.IsAny<Action<IPremiumAdjustmentFinalised>>()), Times.Once);

where bus is a new Mock inserted into the constructor.

But I want to test the values within IPremiumAdjustmentFinalised. I'm finding this really difficult I think mainly because its an interface rather than a concrete class.

We have tried using NServiceBus.Testing to try and inspect the generated event but to no avail.

Does anyone know of how to test the values in the event in this given scenario?

Answer Source

There are 2 solutions that we have come up with

Solution 1:

Create a concrete class that inherits the interface and bus publish that instead

public class PremiumAdjustmentFinalisedEvent : IPremiumAdjustmentFinalised
    public string PolicyNumber { get; set; }
    public decimal Amount { get; set; }
    public DateTime FinalisedOn { get; set; }

This class is only used in the sender, the handler at the other end would still listen for events of the type IPremiumAdjustmentFinalised.

Sending the event would change to this

var message = new PremiumAdjustmentFinalisedEvent
    Amount = AdjustmentAmount,
    PolicyNumber = PolicyNumber,
    FinalisedOn = LastModifiedOn

which allows us to test thus:

bus.Verify(x => x.Publish(It.Is<IPremiumAdjustmentFinalised>(paf => 
    paf.Amount == AdjustmentAmount && 
    paf.FinalisedOn == LastModifiedOn && 
    paf.PolicyNumber == PolicyNumber)), Times.Once);

This is not an ideal solution as we need to add code to the live solution to enable testing, but it works well and is easy to understand.

Solution 2:

Implement our own IBus and assert objects are correct within that:

 class myBus : IBus
     public void Publish<T>(Action<T> messageConstructor)
         IPremiumAdjustmentFinalised paf = new PremiumAdjustmentFinalised();
         var ipaf = (T) paf;

         Assert.AreEqual(paf.Amount, AdjustmentAmount);
         Assert.AreEqual(paf.FinalisedOn, LastModifiedOn);
         Assert.AreEqual(paf.PolicyNumber, PolicyNumber);
     <<Leave the rest of the methods not implemented>>

With my own test implementation of IPremiumAdjustmentFinalised (similar to solution 1 but in the test project)

Now the test looks like this

var myBus = new myBus();
eventPublisher = new AdjustmentFinaliserEventPublisher(myBus);

I like this solution as it does not change the live code just for testing but the downside is that there is a big implementation of IBus with loads of not Implemented methods on it.