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

标签 c# dependency-injection moq autofixture automoq

我将 AutoFixture 与 AutoMoqCustomization 一起使用并尝试创建一个包含只读属性的类的实例:

public override ILog Logger { get; } = LogManager.GetLogger(typeof(MyService));

想法是我应该能够卡住我的测试 ILog测试双重使用:

var log = fixture.Freeze<Mock<ILog>>;

并通过以下方式验证它在主方法调用之后被调用:

log.Verify(l => l.Warn, Times.Once);

然而,当我调用 fixture.Create<MyService> AutoFixture 不会替换 Logger带有模拟 ILog 的属性.我还尝试删除默认值 LogManager.GetLogger<etc>在这种情况下 ILog 的值是null .

其他属性正确填充了测试替身,但这个不是。

作为引用,ILog接口(interface)来自 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);
}

我还验证了手动创建 Mock 并使用 Moq 进行设置是可行的 - ILog属性已正确替换为我的 Mock 使用:

myServiceMock.Setup(s => s.Logger).Returns(myLoggerMock)

任何人都可以阐明这一点吗?

重现步骤

测试

    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());
    }

服务等级 - 注意:通常是 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; }
}
}

如果你在 service.Post(null) 上设置断点行你会看到 ILog属性仍然为空,但其他属性有模拟。

最佳答案

所有 AutoMoqCustomization 所做的就是配置 AutoFixture 以将对接口(interface)或抽象类型的所有请求委托(delegate)给 Moq。它不会自动为创建的测试替身的属性和方法设置任何 stub 。

但是,截至AutoFixture 3.20.0a new auto-mocking customization正是这样做的——AutoConfiguredMoqCustomization:

var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());

启用该自定义可确保将来自 Moq 的测试替身配置为返回由 AutoFixture 从其所有公共(public)属性创建的对象。

但是有一个问题。作为reported by @dcastro , 错误是 introduced in Moq 4.2.1502.911这会导致只读属性——比如你的情况下的MyService.Logger属性——在AutoFixture配置它们之后被Moq覆盖。

因此,即使您切换到 AutoConfiguredMoqCustomizationLogger 属性仍仍为 null,因为它是只读的。另一方面,其他具有返回值的属性和方法将被配置为返回由 AutoFixture 创建的对象。

您现在最好的选择是开始使用 AutoConfiguredMoqCustomization 并降级到 earlier version of Moq其中只读属性仍在正确配置。

关于c# - AutoFixture AutoMoq 不为某些属性创建模拟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33153930/

相关文章:

c# - 如何在 MongoDB 中搜索各种格式的电话号码?

c# - WPF 应用程序文件关联 : DefaultIcon is not working

c# - 如何获取mvc3 Controller 中json数组中的值?

c# - 在 Simple Injector 中注册时设置收集项目的 Lifestyle

nunit - 起订量 : Mocking GetbyId repository method returning null

unit-testing - 单元测试递归函数

c# - MS Test 单元测试引发事件内容

c# - 遍历 XML 文档

unit-testing - Ember 路线单元测试中未知的 `service:session` 注入(inject)器

c# - ASP.NET Core 使用依赖注入(inject)访问其他服务