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