使用 mock 测试 void 方法

Using mock to test a void method

我有一个class

public class NLogRuleComposer : INLogComponentComposer
{
    private LoggingConfiguration _nLogLoggingConfiguration;

    //TODO:  think we need to constructor-inject the logging config 
    public void ComposeComponent(LoggerModel loggerModel
        , LoggingConfiguration nLogLoggingConfiguration
        , string loggerFullName)
    {
        _nLogLoggingConfiguration = nLogLoggingConfiguration;
        var ruleName = loggerFullName;
        var minimumLevel = LogLevel.FromString(loggerModel.level.min_level);
        var maximumLevel = LogLevel.FromString(loggerModel.level.max_level);
        var allTargetsWithLayout = nLogLoggingConfiguration.AllTargets.OfType<TargetWithLayout>().ToList();
        var targetWithoutStackTrace = allTargetsWithLayout
            .FirstOrDefault(x => x.Name.Contains("WithoutStacktrace"));
        var targetWithStackTrace = allTargetsWithLayout.FirstOrDefault(x => x.Name.Contains("WithStacktrace"));
        CreateDefaultLevelFilter(ruleName, maximumLevel.Name, minimumLevel, targetWithoutStackTrace); 
    }

    public void CreateDefaultLevelFilter(string ruleName, string maximumLevelName
        , LogLevel minimumLevel, TargetWithLayout targetWithoutStackTrace)
    {
        var filter = new ConditionBasedFilter();
        filter.Action = FilterResult.Log;
        filter.Condition = "(level <= LogLevel." + maximumLevelName + ")";
        var loggerRule = new LoggingRule(ruleName, targetWithoutStackTrace);
        loggerRule.Filters.Add(filter);
        _nLogLoggingConfiguration.LoggingRules.Add(loggerRule);
    }

现在我想测试CreateDefaultLevelFilter方法,但它是无效的。我不知道如何测试它并测试什么。也许使用 Mock?

未完成的代码:

public class NLogRuleComposerUnitTests
{
    [Theory]
    [InlineData("MyLoggerName")]
    public void NLogRuleComposer_Should_Create_A_LoggingRule(
        string expectedLogger)
    {
        var nLogRuleComposerMock = new Mock<INLogComponentComposer>();
        var nLogTargetMock = new Mock<TargetWithLayout>();
        nLogRuleComposerMock.Setup(x => x.ComposeComponent(It.IsAny<LoggerModel>()
    , It.IsAny<LoggingConfiguration>()
    , It.IsAny<string>()))
    .Verifiable();
    }
}

如果没有一些依赖注入,你将很难测试那段代码。创建这样的实例

var filter = new ConditionBasedFilter();

它不可能进行单元测试,因为作为副作用,您也在测试 class ConditionBasedFilter。理想情况下,您的单元测试不应测试方法结果或行为以外的任何内容。应该模拟外部依赖项。

我会做什么:

  • 创建工厂来构建所有相关 classes 的实例。
  • 在构造函数上注入工厂接口
  • 模拟工厂以控制它们 return 的内容,这样您就可以验证,例如,正确的信息设置为 filter

如果你没有注入依赖的习惯,你应该开始养成这个习惯:)没有它,就不可能正确地进行单元测试。

这是您如何测试 ConditionBasedFilter 属性的示例

var conditionBasedFilter = new ConditionBasedFilter();
var conditionBasedFilterFactoryMock = new Mock<IConditionBasedFilterFactory>
var conditionBasedFilterFactoryMock
     .Setup(f => Create())
     .Returns(conditionBasedFilter);

然后,您在 CreateDefaultLevelFilter 方法中使用这样的工厂

// this factory is injected on contructor
var filter =  _conditionBasedFilterFactory.Create(); 

在测试结束时,您断言已为 ActionCondition 设置了正确的过滤器值。类似适用于 loggerRule