AutoFixture AutoMoq不为某些属性创建模拟

RND*_*hts 4 c# dependency-injection moq autofixture automoq

我正在使用AutoFixture AutoMoqCustomization并尝试创建一个包含readonly属性的类的实例,因此:

public override ILog Logger { get; } = LogManager.GetLogger(typeof(MyService));
Run Code Online (Sandbox Code Playgroud)

这个想法是我应该能够ILog使用以下方法冻结我的测试测试:

var log = fixture.Freeze<Mock<ILog>>;
Run Code Online (Sandbox Code Playgroud)

并验证它在主方法调用之后被调用:

log.Verify(l => l.Warn, Times.Once);
Run Code Online (Sandbox Code Playgroud)

但是,当我调用fixture.Create<MyService>AutoFixture时,不会Logger使用模拟替换属性ILog.我也试图消除默认值LogManager.GetLogger<etc>在这种情况下的价值ILognull.

其他属性正确填充测试双精度但不是这一个.

作为参考,该ILog接口来自ServiceStack的日志框架,如下所示:

public interface ILog
{
    bool IsDebugEnabled { get; }
    void Debug(object message);
    void Debug(object message, Exception exception);
    void DebugFormat(string format, params object[] args);
    void Error(object message);
    void Error(object message, Exception exception);
    void ErrorFormat(string format, params object[] args);
    void Fatal(object message);
    void Fatal(object message, Exception exception);
    void FatalFormat(string format, params object[] args);
    void Info(object message);
    void Info(object message, Exception exception);
    void InfoFormat(string format, params object[] args);
    void Warn(object message);
    void Warn(object message, Exception exception);
    void WarnFormat(string format, params object[] args);
}
Run Code Online (Sandbox Code Playgroud)

我还验证了手动创建Mocks并使用Moq设置它们 - 该ILog属性已被我的Mock正确替换使用:

myServiceMock.Setup(s => s.Logger).Returns(myLoggerMock)
Run Code Online (Sandbox Code Playgroud)

任何人都可以对此有所了解吗?

重现步骤

测试

    using ServiceStack;
    using ServiceStack.Logging;
    using ServiceStack.Web;
    using MyApp;

    [Test]
    public void LogTest()
    {
        var fixture = new Fixture().Customize(new AutoMoqCustomization());

        var log = fixture.Freeze<Mock<ILog>>();
        var request = fixture.Freeze<Mock<IRequest>>();
        var response = new Mock<IResponse>();
        var service = fixture.Create<MyService>();

        request.Setup(r => r.Response).Returns(response.Object);

        service.Post(null);

        log.Verify(l => l.Warn(It.IsAny<string>()), Times.Once());
    }
Run Code Online (Sandbox Code Playgroud)

服务等级 - 注意:通常该Logger属性将是后缀,= LogManager.GetLogger(typeof(MyService))但此时我已将其省略以查看问题.

using ServiceStack;
using ServiceStack.Logging;

namespace MyApp
{
  public class MyService : BaseService
  {
    public override ILog Logger { get; }

    public MyResponse Post(MyRequest request)
    {
        if (request != null) return new MyResponse() {Message = request.Message};

        Logger.Warn("Null request object");
        return null;
    }
   }

public abstract class BaseService : Service
{
    public abstract ILog Logger { get; }
}

public class MyRequest
{
    public string Message { get; set; }
}

public class MyResponse
{
    public string Message { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)

如果您在该service.Post(null)行上断点,您将看到该ILog属性仍为null,但其他属性具有模拟.

Enr*_*lio 6

所有这些AutoMoqCustomization都是配置AutoFixture将所有接口或抽象类型的请求委托给Moq.它不会自动为创建的测试双打的属性和方法设置任何存根.

然而,由于AutoFixture 3.20.0一个新的自动嘲讽定制所做的正是这-的AutoConfiguredMoqCustomization:

var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());
Run Code Online (Sandbox Code Playgroud)

启用该自定义可确保Moq中出现的Test Doubles配置为返回AutoFixture从其所有公共属性创建的对象.

但是有一个问题.正如@dcastro报告的那样,Moq 4.2.1502.911引入了一个错误,该错误导致只读属性(如MyService.Logger您的情况下的属性)在AutoFixture配置后被Moq覆盖.

所以,即使你切换到AutoConfiguredMoqCustomizationLogger属性将仍然为空凭借它被只读的.另一方面,具有返回值的其他属性和方法将配置为返回由AutoFixture创建的对象.

您现在最好的选择是开始使用AutoConfiguredMoqCustomization和降级到早期版本的Moq,其中只读属性仍在正确配置中.