Jake Ginnivan's blog

Verifying Logged Messages With Log4Net

I came across a constructor which looked something like this, just to enable a test to inject a mocked ILog and validate the calls.

ClassCtor(...., Func<ILog> logFactory) { .. }

The log factory would grab inject a log for the class, but everywhere else in the app used

ILog log = LogManager.GetLogger(typeof(CLASS));

There must be a better way, something like a scoped appender or something, so I came up with this syntax

[TestFixture]
public class RecordTest
{
    [Test]
    public void DoTest()
    {
        var testing = Log4NetTestHelper.RecordLog(() =>
        {
            var log = LogManager.GetLogger(typeof (RecordTest));
            log.Error("Testing!");
        });

        Assert.AreEqual("ERROR - RecordTest | Testing!", testing[0]);
    }
}

Pretty easy, you record the logs which are logged inside a lambda. This means you don’t have to inject logs and modify your code if you decide you want to assert on a logged message

The class to do this is pretty simple

public static class Log4NetTestHelper
{
    public static string[] RecordLog(Action action)
    {
        if (!LogManager.GetRepository().Configured)
            BasicConfigurator.Configure();
        var logMessages = new List<string>();
        var root = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root;
        var attachable = root as IAppenderAttachable;

        var appender = new MemoryAppender();
        if (attachable != null)
            attachable.AddAppender(appender);

        try
        {           
            action();
        }
        finally
        {
            var loggingEvents = appender.GetEvents();
            foreach (var loggingEvent in loggingEvents)
            {
                var stringWriter = new StringWriter();
                loggingEvent.WriteRenderedMessage(stringWriter);
                logMessages.Add(string.Format("{0} - {1} | {2}", loggingEvent.Level.DisplayName, loggingEvent.LoggerName, stringWriter.ToString()));
            }
            if (attachable != null)
                attachable.RemoveAppender(appender);
        }

        return logMessages.ToArray();
    }
}

Enjoy!

Comments