Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 10 | Comments: 35

filter by tags archive

Testing Rhino Service Bus applications

time to read 8 min | 1551 words

One of the really nice things about Rhino Service Bus applications is that we have created a structured way to handle inputs and outputs. You have messages coming in and out, as well as the endpoint local state to deal with. You don’t have to worry about how to deal with external integration points, because those are already going over messages.

And when you have basic input/output figured out, you are pretty much done.

For example, let us see the code that handles extending trail licenses in our ordering system:

public class ExtendTrialLicenseConsumer : ConsumerOf<ExtendTrialLicense>
    public IDocumentSession Session { get; set; }
    public IServiceBus Bus { get; set; }

    public void Consume(ExtendTrialLicense message)
        var productId = message.ProductId ?? "products/" + message.Profile;
        var trial = Session.Query<Trial>()
            .Where(x => x.Email == message.Email && x.ProductId == productId)

        if (trial == null)
        trial.EndsAt = DateTime.Today.AddDays(message.Days);
        Bus.Send(new NewTrial
            ProductId = productId,
            Email = trial.Email,
            Company = trial.Company,
            FullName = trial.Name,
            TrackingId = trial.TrackingId

How do we test something like this? As it turns out, quite easily:

public class TrailTesting : ConsumersTests
    protected override void PrepareData(IDocumentSession session)
        session.Store(new Trial
            Email = "you@there.gov",
            EndsAt = DateTime.Today,
            ProductId = "products/nhprof"

    public void Will_update_trial_date()
        Consume<ExtendTrialLicenseConsumer, ExtendTrialLicense>(new ExtendTrialLicense
            ProductId = "products/nhprof",
            Days = 30,
            Email = "you@there.gov",

        using (var session = documentStore.OpenSession())
            var trial = session.Load<Trial>(1);
            Assert.Equal(DateTime.Today.AddDays(30), trial.EndsAt);

    // more tests here

All the magic happens in the base class, though:

public abstract class ConsumersTests : IDisposable
    protected IDocumentStore documentStore;
    private IServiceBus Bus = new FakeBus();

    protected ConsumersTests()
        documentStore = new EmbeddableDocumentStore
            RunInMemory = true,
            Conventions =
                    DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites

        IndexCreation.CreateIndexes(typeof(Products_Stats).Assembly, documentStore);

        using (var session = documentStore.OpenSession())

    protected T ConsumeSentMessage<T>()
        var fakeBus = ((FakeBus)Bus);
        object o = fakeBus.Messages.Where(x => x.GetType() == typeof(T)).First();

        return (T) o;

    protected void Consume<TConsumer, TMsg>(TMsg msg)
        where TConsumer : ConsumerOf<TMsg>, new()
        var foo = new TConsumer();

        using (var documentSession = documentStore.OpenSession())
            Set(foo, documentSession);
            Set(foo, Bus);
            Set(foo, documentStore);



    private void Set<T,TValue>(T foo, TValue value)
        PropertyInfo firstOrDefault = typeof(T).GetProperties().FirstOrDefault(x=>x.PropertyType==typeof(TValue));
        if (firstOrDefault == null) return;
        firstOrDefault.SetValue(foo, value, null);

    protected virtual void PrepareData(IDocumentSession session)

    public void Dispose()

And here are the relevant details for the FakeBus implementation:

public class FakeBus : IServiceBus
    public List<object>  Messages = new List<object>();

    public void Send(params object[] messages)

Now, admittedly, this is a fairly raw approach and we can probably do better. This is basically hand crafted auto mocking for consumers, and I don’t like the Consume<TConsumer,TMsg>() syntax very much. But it works, it is simple and it doesn’t really gets in the way.

I won’t say it is the way to go about it, but it is certainly easier than many other efforts that I have seen. We just need to handle the inputs & outputs and have a way to look at the local state, and you are pretty much done.


Comment preview

Comments have been closed on this topic.


  1. Production postmortem: The case of the memory eater and high load - about one day from now
  2. Production postmortem: The case of the lying configuration file - 3 days from now
  3. Production postmortem: The industry at large - 4 days from now
  4. The insidious cost of allocations - 5 days from now
  5. Find the bug: The concurrent memory buster - 6 days from now

And 4 more posts are pending...

There are posts all the way to Sep 10, 2015


  1. Find the bug (5):
    20 Apr 2011 - Why do I get a Null Reference Exception?
  2. Production postmortem (10):
    14 Aug 2015 - The case of the man in the middle
  3. What is new in RavenDB 3.5 (7):
    12 Aug 2015 - Monitoring support
  4. Career planning (6):
    24 Jul 2015 - The immortal choices aren't
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats