NLog and Unit Testing

11,921

Solution 1

I found that all the configuration resides within a app.config for a Unit Test Project as opposed to the NLog.Config file. Be sure to declare the config section and then the NLog configuration. Below is my sample app.config

    <configuration>
      <configSections>

         <section name="nlog"
                    type="NLog.Config.ConfigSectionHandler, NLog"/>
  </configSections>
  <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <targets>


      <target name="file" xsi:type="File"
             layout="${longdate} ${logger} ${message}"
             fileName="${basedir}/logs/${shortdate}.log" />

    </targets>
   <rules>
       <logger name="*" minlevel="Trace" writeTo="file"/>

    </rules>

  </nlog>
</configuration>

Solution 2

When executing units test in parallel, then it is a good idea to use isolated NLog LogFactory for each parallel execution:

LogFactory logFactory = new LogFactory();
logFactory.Configuration = new XmlLoggingConfiguration(configFilePath, true, logFactory); 
Logger logger = logFactory.GetCurrentClassLogger();

See also https://github.com/NLog/NLog/wiki/Configure-component-logging

If you need to load NLog config from a string instead of a file:

string currentDir = System.IO.Directory.GetCurrentDirectory();
System.IO.StringReader sr = new System.IO.StringReader(xmlString);
System.Xml.XmlReader xr = System.Xml.XmlReader.Create(sr);
logFactory.Configuration.Configuration = new NLog.Config.XmlLoggingConfiguration(xr, currentDir);

See also https://github.com/NLog/NLog/wiki/Explicit-NLog-configuration-loading

Solution 3

Not sure if this is the problem, but pretty sure it is:

Reading the NLog.config from an unit test environment could be difficult, therefor is more robust to read the config from string in the unit tests. We use the helper:

    protected XmlLoggingConfiguration CreateConfigurationFromString(string configXml)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(configXml);

        return new XmlLoggingConfiguration(doc.DocumentElement, Environment.CurrentDirectory);
    }

and then:

 LogManager.Configuration = CreateConfigurationFromString(@"
            <nlog throwExceptions='true'>
                <targets><target name='debug' type='debug' layout='${message}' /></targets>
                <rules>
                    <logger name='*' minlevel='info' appendto='debug'>
                        <filters>
                            <whencontains layout='${message}' substring='msg' action='ignore' />
                        </filters>
                    </logger>
                </rules>
            </nlog>");

don't forget to reset the LogManager.Configuration before or after each test.

Update : enabled throwExceptions in config.

Also about the error. You need probably an absolute path in the unit test.

Share:
11,921
TheNoob
Author by

TheNoob

()=&gt;{};

Updated on June 07, 2022

Comments

  • TheNoob
    TheNoob almost 2 years

    I am using NLog for my logger. Everything works fine when logging when I run an .exe, or even debug through Visual Studio, NLog will still write to the file.

    But, if I run an object that calls the logger through a Unit test, the file is created but it is empty. Is there an extra setting/rule I need to add to the config to have NLog write to files under unit tests?

    I could mock NLog for this and not have log dumps, but I'd like to see if I can get this to work before I decide to just mock NLog. Even though this is only happening in unit tests and is working otherwise, here is my config and code for logging. I left out the filenames.

    public static void Info(string app, string m)  => EngineLogger.Logger.Info($"{app} : {m}");
    
    
    
    <targets>
        <target name="infoFile"
                xsi:type="File"
                layout="${date:format=yyyy-MM-dd HH\:mm\:ss} ${pad:padding=5:inner=${level:uppercase=true}} ${logger} ${message}"
                fileName="leftoutForQuestion"
                keepFileOpen="false"
                encoding="iso-8859-2" />
        <target name="errorFile"
                xsi:type="File"
                layout="${date:format=yyyy-MM-dd HH\:mm\:ss} ${pad:padding=5:inner=${level:uppercase=true}} ${logger} ${message}"
                fileName="leftOutForQuestion"
                keepFileOpen="false"
                encoding="iso-8859-2" />
      </targets>
      <rules>
        <logger name="*" minlevel="Debug" maxlevel="Info" writeTo="infoFile" />
        <logger name="*" minlevel="Warn" maxlevel="Fatal" writeTo="errorFile" />
      </rules>
    

    Here is the error from internal log:

    Error Error has been raised. Exception: System.Runtime.InteropServices.COMException (0x800700A1): The specified path is invalid. (Exception from HRESULT: 0x800700A1)
       at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
       at NLog.Internal.FileAppenders.BaseFileAppender.WindowsCreateFile(String fileName, Boolean allowFileSharedWriting)
       at NLog.Internal.FileAppenders.BaseFileAppender.TryCreateFileStream(Boolean allowFileSharedWriting)
       at NLog.Internal.FileAppenders.BaseFileAppender.CreateFileStream(Boolean allowFileSharedWriting)
       at NLog.Internal.FileAppenders.RetryingMultiProcessFileAppender.Write(Byte[] bytes)
       at NLog.Targets.FileTarget.WriteToFile(String fileName, LogEventInfo logEvent, Byte[] bytes, Boolean justData)
       at NLog.Targets.FileTarget.ProcessLogEvent(LogEventInfo logEvent, String fileName, Byte[] bytesToWrite)
       at NLog.Targets.FileTarget.Write(LogEventInfo logEvent)
       at NLog.Targets.Target.Write(AsyncLogEventInfo logEvent)
    
  • TheNoob
    TheNoob over 7 years
    Oh nice thanks for your reply! I will give this a try and let you know. =) thanks again
  • TheNoob
    TheNoob over 7 years
    i tried this solution but the same problem still happens. thanks for your input though =) much appreciated
  • Webezine
    Webezine over 7 years
    Have you tried turning debug on within nlog and see if anything is logged in internal nlog file?
  • Michael Freidgeim
    Michael Freidgeim about 2 years
    “ reset the LogManager.Configuration before or after each test.” -not enough , if tests can run in parallel. Consider to use logFactory as suggested by Rolf Kristensen above