Home > CruiseControl.Net, NLog > Unit Testing Logging

Unit Testing Logging

As part of the upgrade we’re planning on making to CruiseControl.NET we are using NLog for logging messages. We are also aiming to increase the unit test coverage of the code. So the question arises – how can we test that logging is actually working as it should be?

There’s actually two parts to this question:

  1. Are the logs being generated correctly?
  2. Are we putting the right stuff in the logs?

Question #1 is really outside our scope – considering the number of different ways the logging can be configured we’d have to duplicate all the tests in NLog itself. So rather than doing this we’re just going to assume that the tests in NLog will pick up any errors with log generation.

That leaves the second question – how can we know we are putting the right stuff into the logs? The short answer is we can’t – but then there is no way that we can guarantee that any code we write is 100% correct!

Instead what I’m interested in doing is checking that we are logging some expected stuff. In other words how can we intercept the logging to ensure that we are logging the expected messages?

To answer this question we need a little bit of background. Logging in NLog can be configured either via a configuration file or via code. Now the recommended way is the config file so it can be changed without forcing a re-compile. But for us the way that we will use is via code.

NLog also has the concept of Targets: where the output is written to. There is a wide variety of different targets for different scenarios (console, file, e-mail, database, etc.) Of interest in unit testing is the Memory target. This will write the log messages to an array in memory.

So all we need is some way to wire up the logging to a memory target and then check the messages that are being written. It would also be nice if the unit tests reset the logging after they’ve finished just in case there has been some configuration in the unit test config file.

To make this easy I have added a helper class to our unit tests that simplifies this whole process. This is a disposable class with a static method for initialising the whole process. To use this class looks something like:

using (var intercept = LogHelper.InterceptLogging(typeof(TypeBeingTested)))
{
    // Tests go here
    var expected = new[]
                        {
                            // Expected messages go here
                            "LogLevel|TypeBeingTested|Message"
                        };
    CollectionAssert.AreEqual(expected, intercept.Messages);
}

Since the class implements IDisposable it can be used in a using statement. This will ensure that the configuration is reset after the tests have finished.

The static method takes in an array of types. These types are the loggers that should be intercepted – after all there can be other messages occurring that we don’t want to intercept.

To actually check the results we need to compare the Messages property on the class with the expected messages. This is just a facade property that exposes the messages from the underlying memory target. As in the example above the messages consist of three parts: loglevel (e.g. debug, info, error, etc.), the loggger (this will be one of the types in the array) and the actual message.

Nice and simple, without adding too much overhead to the testing process.

Let me know if anyone is interested in the actual code behind LogHelper and I will post it. Otherwise it is in the Subversion repository for CruiseControl.NET.

About these ads
Categories: CruiseControl.Net, NLog Tags:
  1. 11 May, 2011 at 1:54 am | #1

    Hi Craig, great blog!
    I am in the midst of writing unit tests to verify that log messages are written to the log under certain conditions. Could you please post your source code for the LogHelper class as it may come in very handy indeed :-)
    Cheers, Jones

    • Craig Sutherland
      11 May, 2011 at 6:19 am | #2

      Hi Jones,

      All the code is in Subversion on SourceForge. You can view the source online at .

      Craig

      • 11 May, 2011 at 8:32 pm | #3

        Hi Craig, I found it and I’m working on my first test with it, thanks again.
        Cheers, Jones

      • 11 May, 2011 at 8:46 pm | #4

        Hi again, Craig, are you using NLog 2.0 ?

        • Craig Sutherland
          11 May, 2011 at 9:36 pm | #5

          Yes – NLog 2.0. Not sure what would be needed to convert to a different version – I can’t remember what I did for the previous version of NLog :-(

          Craig

          • 11 May, 2011 at 10:53 pm | #6

            Thank you for the quick reply. I got it working by changing type of the Messages property from IList to ArrayList.
            Cheers, Jones

  2. Ruben Willems
    7 January, 2011 at 7:45 am | #7

    That’s indeed a very neat way of testing logging.
    Do we really need it? I mean testing the logging itself.

    What would the benefit be of the following scenario :
    ° existing code logs ‘Project X starts integration’
    ° I update the logging to ‘Project X starts integration at HH:MM’

    and now some tests fail, because I updated the log message. What is the added value?
    Do not get me wrong, I really like testing, but I wonder if testing log messages is not a bit over the top?

    It is not that these log messages will be used as input or so for another program or whatever. If it would be that case, than I can understand that we test it. But than it would not be ‘log’ messages anymore, but real data.

    • Craig Sutherland
      7 January, 2011 at 8:04 am | #8

      For me the main point is to test that we are logging messages. There are parts of the code that do nothing other than log messages (e.g. some warnings, the null task, etc.) There are also some cases where we are interested in what messages are produced, for example checking the flow of logic between different components.

      The other use that testing logging is as a safety net. In some places we have specific messages (e.g. errors) and we want to ensure that they are not lost.

      So I don’t think we should go overboard and test every log message that is being generated. Instead we should just be targeting the cases where it will provide value.

      Craig

      • Ruben Willems
        7 January, 2011 at 8:08 am | #9

        Good point : testing the error messages is indeed a plus.
        It’s like creating a unit test where you expect a certain exception or exception message, and we want to be sure that it gets logged also.
        That’s indeed added value :-)

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: