使用 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();
在测试结束时,您断言已为 Action
和 Condition
设置了正确的过滤器值。类似适用于 loggerRule
我有一个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();
在测试结束时,您断言已为 Action
和 Condition
设置了正确的过滤器值。类似适用于 loggerRule