0

I have a logger class, which purpose is to be called from whatever class in my solution, who decides to log something. I added an interface, which is why I applied a singleton pattern, and didn't use a static class.

My LogManager implementation (singleton): https://pastebin.com/NHKmbj9c

I wanted to write simple unit tests, which are supposed to use local variables, testing the functionality of each ILogger methods, but as soon as my first Unit has passed, the Singleton will stay initialized in context, making subsequent unit tests to fail (while they are trying to Initialize the singleton...).

Unit Test:

[TestClass]
public class LogManagerTests
{
    [TestMethod]
    public void Error_ExpectedErrorLevel_ShouldBe_Error()
    {
        // Arrange
        var actualLevel = ErrorLevel.Warning;
        const ErrorLevel expectedLevel = ErrorLevel.Error;
        var iLogger = LogManager.GetInstance;
        iLogger.Initialize((level, msg) => { actualLevel = level; }, null);

        // Act
        iLogger.Error(new Exception(), string.Empty);

        // Assert
        Assert.AreEqual(expectedLevel, actualLevel);
    }

    [TestMethod]
    public void Debug_ExpectedErrorLevel_ShouldBe_Verbose()
    {
        // Arrange
        var actualLevel = ErrorLevel.Warning;
        const ErrorLevel expectedLevel = ErrorLevel.Verbose;
        var iLogger = LogManager.GetInstance;
        iLogger.Initialize(null, (level, msg, ex) => { actualLevel = level; });

        // Act
        iLogger.Debug(string.Empty);

        // Assert
        Assert.AreEqual(expectedLevel, actualLevel);
    }
}

Another tought is to initialize the LogManager as a private global variable within my TestClass, but this could give race conditions if the Unit test runs async, as multiple methods then will access the same output variable, which may override each others.

Is it possible to UnitTest a singleton in any way?

The design does not allow me to refactor the LogManager, and remove the singleton pattern from it.

grmihel
  • 784
  • 3
  • 15
  • 40
  • Could help : https://stackoverflow.com/questions/5897681/unit-testing-singletons Short answer : Don't use singletons – rak007 May 22 '18 at 14:16

1 Answers1

0

It's possible to unit test a singleton, you just need to think about it differently. Don't try so hard to change your methodology to fit the test. Think about creating a method that is used only for testing, LogManager.Uninitialize(). Call this after every test in this group of tests to ensure your singleton is set back to a testable state.

[TestCleanup()]
public void Cleanup()
{
     LogManager.Uninitialize();
}

It may not be pure but I think it's fine to write in a diagnostics method every once in a while. It's better than having bad test coverage where you need good test coverage.

Kyle B
  • 2,328
  • 1
  • 23
  • 39