简体   繁体   English

单元测试中的模拟日志单例

[英]Mock Log Singleton in Unit Test

I have a logger class, which purpose is to be called from whatever class in my solution, who decides to log something. 我有一个logger类,该类的目的是从解决方案中决定记录某些内容的任何类中调用。 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 我的LogManager实施(单个): 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...). 我想编写简单的单元测试,应该使用局部变量来测试每个ILogger方法的功能,但是一旦我的第一个单元通过,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. 另一个难点是将LogManager初始化为我的TestClass中的私有全局变量,但这会在单元测试异步运行时提供竞争条件,因为多个方法随后将访问相同的输出变量,这可能会相互覆盖。

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. 该设计不允许我重构LogManager并从中删除单例模式。

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() . 考虑创建一个仅用于测试的方法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. 这比在需要良好测试覆盖率的情况下覆盖不良的测试覆盖率更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM