模拟基地 class 受保护 属性
Mocking base class protected property
我目前正在创建一个 Mock
单元测试来测试 LogManager
Logger.Error()
调用 class 方法,如下所示。
public class Test : BaseClass
{
public override void DoSomething(object value)
{
try
{
if (value == null)
{
throw new Exception();
}
}
catch(exception ex)
{
Logger.Error("Exception raised!", ex);
}
}
}
我的 class 使用抽象基础 class,它有一个 属性 定义如下 ILog
public abstract class BaseClass
{
protected ILog Logger => LogManager.GetLogger(GetType());
}
问题是如何模拟这个基数 class 属性 Logger
以便我可以测试 Logger.Error()
是否被引发?
这是我的单元测试
[Test]
public void PassingNullParamShouldRaiseError()
{
// Arrange
var mockLog = new Mock<ILog>();
var sut = new Test();
// Action
sut.DoSomething(null);
// Assert
mockLog.Verify(x => x.Error("Exception raised!"), Times.Once());
}
如果你使基础属性虚拟
public abstract class BaseClass {
protected virtual ILog Logger => LogManager.GetLogger(GetType());
}
您现在可以使用可在测试时使用的模拟覆盖 属性
[Test]
public void PassingNullParamShouldRaiseError() {
// Arrange
var mockLog = new Mock<ILog>();
var sut = new Mock<Test>() {
CallBase = true //Important to be able to call base member
};
//override default behavior of protected logger
sut.Protected()
.Setup<ILog>("Logger")
.Returns(mockLog.Object);
// Act
sut.Object.DoSomething(null);
// Assert
mockLog.Verify(x => x.Error("Exception raised!", It.IsAny<Exception>()), Times.Once());
}
现在理想情况下,您的基础 class 不应像目前使用 LogManager
那样与静态实现问题紧密耦合
记录器应该显式地注入依赖 class。或者至少通过日志工厂抽象,
public interface ILoggerFactory {
ILog GetLogger(Type type);
}
谁的实现可以包装那种代码味道
public class DefaultLoggerFactory : ILoggerFactory {
public ILog GetLogger(Type type) => LogManager.GetLogger(type);
}
可以用来获取想要的日志
public class Test {
private readonly ILog logger;
public Test(ILoggerFactory logs) {
logger = logs.GetLogger(GetType());
}
public void DoSomething(object value) {
try {
if (value == null) {
throw new Exception();
}
} catch (Exception ex) {
logger.Error("Exception raised!", ex);
}
}
}
我目前正在创建一个 Mock
单元测试来测试 LogManager
Logger.Error()
调用 class 方法,如下所示。
public class Test : BaseClass
{
public override void DoSomething(object value)
{
try
{
if (value == null)
{
throw new Exception();
}
}
catch(exception ex)
{
Logger.Error("Exception raised!", ex);
}
}
}
我的 class 使用抽象基础 class,它有一个 属性 定义如下 ILog
public abstract class BaseClass
{
protected ILog Logger => LogManager.GetLogger(GetType());
}
问题是如何模拟这个基数 class 属性 Logger
以便我可以测试 Logger.Error()
是否被引发?
这是我的单元测试
[Test]
public void PassingNullParamShouldRaiseError()
{
// Arrange
var mockLog = new Mock<ILog>();
var sut = new Test();
// Action
sut.DoSomething(null);
// Assert
mockLog.Verify(x => x.Error("Exception raised!"), Times.Once());
}
如果你使基础属性虚拟
public abstract class BaseClass {
protected virtual ILog Logger => LogManager.GetLogger(GetType());
}
您现在可以使用可在测试时使用的模拟覆盖 属性
[Test]
public void PassingNullParamShouldRaiseError() {
// Arrange
var mockLog = new Mock<ILog>();
var sut = new Mock<Test>() {
CallBase = true //Important to be able to call base member
};
//override default behavior of protected logger
sut.Protected()
.Setup<ILog>("Logger")
.Returns(mockLog.Object);
// Act
sut.Object.DoSomething(null);
// Assert
mockLog.Verify(x => x.Error("Exception raised!", It.IsAny<Exception>()), Times.Once());
}
现在理想情况下,您的基础 class 不应像目前使用 LogManager
记录器应该显式地注入依赖 class。或者至少通过日志工厂抽象,
public interface ILoggerFactory {
ILog GetLogger(Type type);
}
谁的实现可以包装那种代码味道
public class DefaultLoggerFactory : ILoggerFactory {
public ILog GetLogger(Type type) => LogManager.GetLogger(type);
}
可以用来获取想要的日志
public class Test {
private readonly ILog logger;
public Test(ILoggerFactory logs) {
logger = logs.GetLogger(GetType());
}
public void DoSomething(object value) {
try {
if (value == null) {
throw new Exception();
}
} catch (Exception ex) {
logger.Error("Exception raised!", ex);
}
}
}