HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Unit-testing event aggregator

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
testingaggregatorunitevent

Problem

I have written event aggregator with the following API (just for the fun of it, I am aware that nuget has like 100 similar implementations):

/// 
/// Events aggregator
/// 
public interface IMessenger
{
    /// 
    /// Subscribes an object to all relevant events.
    /// 
    /// Object, that implements one or more IListener interfaces
    /// Subscription handle. Dispose to unsubscribe.
    IDisposable Subscribe(object listener);

    /// 
    /// Subscribes a delegate to TMessage event.
    /// 
    /// Event handler.
    /// Subscription handle. Dispose to unsubscribe.
    IDisposable Subscribe(Action handler)
        where TMessage : IMessage;

    /// 
    /// Sends message to event pipeline.
    /// 
    /// Message to send.
    /// Awaitable task, that returns true if message was processed successfully. Otherwise - false.
    Task PublishAsync(IMessage message);
}

/// 
/// Message that can be delivered to subscribers via IMessenger.
/// 
public interface IMessage
{
    /// 
    /// Whether or not message was handled by subscriber.
    /// 
    bool Handled { get; set; }
}

/// 
/// Implementaions of this interface are recognized by IMessenger as event handlers for TMessage.
/// 
/// Type of message.
public interface IListener where TMessage : IMessage
{
    /// 
    /// This method is called by IMessenger when TMessage is published.
    /// 
    /// Message received by IMessenger.
    void Handle(TMessage message);
}


And here are some unit tests I have written in order to test my implementation:

```
[TestFixture]
class MessengerTests
{
[Test]
public void Subscribe_OnNullListener_Throws()
{
var messenger = new Messenger();
IListener listener = null;
Assert.Throws(() => messenger.Subscribe(listener));
}

[Test]
public void Subscribe_OnNotListener_Throws()
{
var messenger = new Messenger();
var listener = new object();
Assert.Throws(() => messenger.Subscribe(listener));

Solution

The tests should be easy to maintain and understand. That is the tool that drives development. Sometimes it may contradict with the widely known rules you mentioned, but it does not mean we should be fanatic about that (as soon as the tests drive the development and work as the safety net).

-
That's totally fine and even more - introducing 'common' initialization logic increases coupling of your unit tests. Imagine you need to add a new 'common' line to setup things common for a few tests. You never know for sure if there are any other tests impacted; you may make your tests false positive. It's more safe to modify your test 1 by 1 as necessary.

-
Tests like Publish_OnMessageSent_HandledMessageIsIgnored have about 6-7 arrange lines and 2 assertions. IMO, it is easier to read, understand and (!) maintain this single test than splitting it into two (or more) just because of the 'one assertion per test' rule.

-
That looks like Facade tests. That might be fine to have them at some level, but it's important to understand that tests like that may be a bit more hard to maintain since there are more parts that might be broken during refactoring.

-
Don't have any oppinion on that... Looks fine to me.

Context

StackExchange Code Review Q#163456, answer score: 2

Revisions (0)

No revisions yet.