So regards logging from SO and other sites on the Internet the best response seems to be:
void DoSomething() {
Logger.Log(\"Doing something!\");
// Code.
I've only ever written a few unit tests for logging. It's a pain, either making the production code messy (due to injecting the logger) or the test smelly (replacing the static logger with a mock). Unlike McWafflestix, I've often not found it to be worth the effort afterwards.
How much do you really want to know whether the logging is working, beyond what you'll see through other (hands-on) testing? You might want to use DI for the occasional class where logging is really important, but otherwise I just wouldn't bother testing logging.
This is assuming the log is of a debug nature - if it's an audit log or something like that (something with a functional requirement) that's a different matter.
Personally I think its overkill to unit test logging statements. But if you really want to do it then a mock logger would work or, if using a framework like log4j, write a custom appender that is used during test runs.
Most logging frameworks allow you to provide custom implementation for components. You can use that configuration mechanism to provide your own implementations.
For instance, Java's Log4J allows you to declare custom appenders, which are the components responsible for 'delivering' a LoggingEvent.
A logger can be easily mocked and injected using:
Appender appenderMock = EasyMock.createMock(Appender.class);
/* expect */ appenderMock.doAppend(EasyMock.isA(LoggingEvent.class));
EasyMock.replay(appenderMock);
Logger.getLogger(/* replace with your own */"My logger").addAppender(appenderMock);
EasyMock.verify(appenderMock);
This test only verifies that a logging event is sent, but you can refine it much more using EasyMock.
Although I agree with others that I wouldn't apply TDD to logging, I would try to ensure that unit testing covers all code paths that contain logging statements. And importantly ensure that the highest verbosity level is configured while running the unit tests, so that all logging statements are executed.
For example, the following code has a bug which will throw a FormatException only if if Debug level tracing is enabled.
if (logger.IsDebugEnabled)
{
string message = String.Format(CultureInfo.CurrentCulture,
"... {1} ...", someValue);
logger.Debug(message);
}
I usually do not unit test logging statements by asserting on what's logged but I check that the code paths taken by my unit tests cover logging statements just to make sure that I don't get an exception while logging an exception!
I would probably have a separate body of unit tests for the logger itself, to test out its various functions separately from everything else. In methods that are using the logger, I would just test that the logger was invoked (i.e. expect that it was called) with the right parameters. For example, if I have a method:
DoSomething()
{
if (FatalErrorOccurred)
{
Logger.Log("Fatal Error", ErrorLevel.Fatal);
}
}
I would write a test that shows the logger logged a fatal error message when FatalErrorOccurred was true. I would not, of course, test the contents of the error message itself, as that is very susceptible to change.