Thursday 23 October 2008

Unit Testing the Enterprise Library #1 - Unit Testing the Logging Application Block

So I've decided that using the enterprise library in my application is a great idea. We're also following TDD and I'm using a design pattern called Object Method to abstract the implementation of my framework classes from my application. But I've come across a problem. When I'm unit testing my implementation I find that it's very difficult to unit test the implementation of the Enterprise Library. Then I came across this article by Mark Seemann showing how to unit test the Logging Application block. It's very simple really, you create a custom logging trace listener in your test project and have the custom listener store all log messages in a list you can unit test later. What the article was not specific about was the implementation of the enterprise library in your test project. If you add an app.config file to your test project then your test library will load the config settings from the test project's app.config file. Add your custom block to the test project and add the trace listener to the "All Events" section and it should work just fine. So for example, this is Mark Seemann's custom trace listener:
   1: ///
   2: /// This is a custom trace listener that loads the trace information into a
   3: /// list of entries in the log file.
   4: /// Found here: http://blogs.msdn.com/ploeh/archive/2006/04/06/UnitTestYourEnterpriseLibraryLoggingLogic.aspx
   5: /// Author: Mark Seemann
   6: ///
   7: [ConfigurationElementType(typeof(CustomTraceListenerData))]
   8: public class StubTraceListener : CustomTraceListener
   9: {
  10:     private readonly static List logEntries_ = new List();
  11:     private readonly static List logMessages_ = new List();
  12:     
  13:     public override void Write(string message)
  14:     {
  15:         StubTraceListener.logMessages_.Add(message);
  16:     }
  17:     
  18:     public override void WriteLine(string message)
  19:     {
  20:         StubTraceListener.logMessages_.Add(message);
  21:     }
  22:     
  23:     public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
  24:     {
  25:          LogEntry le = data as LogEntry;
  26:         
  27:          if (le != null)
  28:          {
  29:              StubTraceListener.logEntries_.Add(le);
  30:         
  31:              if (this.Formatter != null)
  32:              {
  33:                  this.Write(this.Formatter.Format(le));
  34:                  return;
  35:              }
  36:          }
  37:         
  38:          base.TraceData(eventCache, source, eventType, id, data);
  39:     }
  40:     
  41:     internal static IList GetLogMessages()
  42:     {
  43:          return new ReadOnlyCollection(StubTraceListener.logMessages_);
  44:     }
  45:     
  46:     internal static IList GetLogEntries()
  47:     {
  48:          return new ReadOnlyCollection(StubTraceListener.logEntries_);
  49:     }
  50:     
  51:     internal static void Reset()
  52:     {
  53:          StubTraceListener.logEntries_.Clear();
  54:          StubTraceListener.logMessages_.Clear();
  55:     }
  56: }
And here is my test case:
   1: [TestMethod()]
   2: public void WarningTest()
   3: {
   4:     EntLibLogger target = new EntLibLogger();
   5:     string message = "warning message";
   6:     LogPriority priority = LogPriority.Low;
   7:     CallingMethod callingMethod = new CallingMethod();
   8:     
   9:     target.Warning(message, priority, callingMethod);
  10:     IList entries = StubTraceListener.GetLogEntries();
  11:     
  12:     Assert.IsNotNull(entries);
  13:     Assert.AreEqual(1, entries.Count);
  14:     Assert.AreEqual((int)priority, entries[0].Priority);
  15:     Assert.AreEqual(message, entries[0].Message);
  16: }

I'm not testing much, but you can extend your test cases to test as much as you need. Just make sure you have an app.config file in your test project liks so:

And that you've used the LAB to setup your custom trace listener:

No comments: