c# - Unit Testing using Moq and Autofac -
i have following logger logger class , want know best unit testing it.
some observations:
- i needed create interface ifilewrapper in order break dependency system.io dependency , been able user dependency injection (autofac)
 i able unit testing method filewrapper.writelog implementing ifilewrapper using memorystring if wanted test expected behavior inside method won't able (e.g: throwing exceptions, incorrect path , filename, etc.)
/// <summary> /// creates instance of type <see cref="filelogger"/> /// </summary> /// <remarks>implements singleton pattern</remarks> private filelogger() { filename = string.format("\\{0: mmm dd, yy}.log", datetime.now); path = environment.currentdirectory; filewrapper = containerbuilderfactory.container.resolve<ifilewrapper>(); } /// <summary> /// log <paramref name="message"/> in <paramref name="path"/> specified. /// <paramref name="username"/>, <paramref name="host"/> must supplied /// </summary> /// <example> /// <code> /// var handler = new loggerhandlerfactory(); /// var logger = handler.gethandler<filelogger>(); /// logger.log("hello csharplogger"); /// </code> /// </example> /// <exception cref="argumentnullexception"></exception> /// <exception cref="argumentexception"></exception> /// <exception cref="notsupportedexception"></exception> /// <exception cref="filenotfoundexception"></exception> /// <exception cref="ioexception"></exception> /// <exception cref="securityexception"></exception> /// <exception cref="directorynotfoundexception"></exception> /// <exception cref="unauthorizedaccessexception"></exception> /// <exception cref="pathtoolongexception"></exception> /// <exception cref="argumentoutofrangeexception"></exception> /// <exception cref="formatexception"></exception> public void log(string message, loglevel level = loglevel.info) { lock (_current) { var configlevel = csharploggerconfiguration.configuration.getloglevel(); if (configlevel != loglevel.off & level != loglevel.off && configlevel >= level) { try { filewrapper.writelog(string.concat(path, filename), message, level); } catch (csharploggerexception) { throw; } } } }
so, created following unittesting using moq:
 //arrange         csharploggerconfiguration.configuration.setloglevel(loglevel.debug);          var mock = new mock<ifilewrapper>();         mock.setup(x => x.writelog(it.isany<string>(), it.isany<string>(), it.isany<loglevel>()));          logger.filewrapper = mock.object;          //act         logger.log("hello csharplogger", loglevel.debug);         logger.log("hello csharplogger", loglevel.warn);          //assert          mock.verify(x => x.writelog(it.isany<string>(), it.isany<string>(), it.isany<loglevel>()), times.exactly(2));   so far good. i'm not confortable line: logger.filewrapper = mock.object; keep filewrapper propety private.
any advise welcome.
i'll publishing code http://csharplogger.codeplex.com/ in case want more details.
use constructor injection. in short; instead of providing service (in case file wrapper) setting property, make logger have public constructor takes ifilewrapper argument.
public class logger {     public logger(ifilewrapper filewrapper)     {         filewrapper = filewrapper;     }      public ifilewrapper filewrapper { get; } }  // in test: var logger = new logger(mock.object);   to answer question having singleton file wrapper more thoroughly, here's code sample application (non-test) code:
public static class filewrapperfactory {     private static ifilewrapper _filewrapper;      public static ifilewrapper getinstance()     {         return _filewrapper ?? (_filewrapper = createinstance());     }      private static ifilewrapper createinstance()     {         // necessary setup here         return new filewrapper();     } }   public class stuffdoer {     public void dostuff()     {         var logger = new filelogger(filewrapperfactory.getinstance());          logger.writelog("starting stuff...");          // stuff          logger.writelog("stuff done.");     } }   since filewrapperfactory maintains static instance of file wrapper, you'll never have more one. however, can create multiple loggers that, , don't have care. if you, in future, decide it's ok have many file wrappers, logger code doesn't have change.
in real-world application, i'd advice choose kind of di framework handle book-keeping you; have excellent support singleton instances, doing filewrapperfactory above (but in more sophisticated , robust way. filewrapperfactory isnt' thread-safe, example...).
Comments
Post a Comment