【问题标题】:AutoFixture AutoMoq not creating mocks for some propertiesAutoFixture AutoMoq 不为某些属性创建模拟
【发布时间】:2015-10-15 16:36:16
【问题描述】:

我正在使用带有 AutoMoqCustomization 的 AutoFixture 并尝试创建一个包含只读属性的类的实例:

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

我的想法是我应该能够冻结我的测试ILog test double 使用:

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

并验证它是在 main 方法调用之后通过以下方式调用的:

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

但是,当我调用 fixture.Create&lt;MyService&gt; 时,AutoFixture 不会将 Logger 属性替换为 ILog 的模拟。我还尝试删除默认值LogManager.GetLogger&lt;etc&gt;,在这种情况下ILog 的值是null。

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

作为参考,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);
}

我还验证了手动创建 Mocks 并使用 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 属性仍然为空,但其他属性有模拟。

【问题讨论】:

  • 具有Logger 属性的类是具体类吗? AutoMoq 不代理具体类:blog.ploeh.dk/2010/08/25/…
  • 嗨,马克,这是一个具体的类,所以我同意你的观点,但如果是这样的话,为什么 AutoMoq 会自动填充同一类的所有其他属性?
  • 我不知道,因为你没有给我看复制品...
  • 已添加重现步骤。
  • 其他属性是什么意思?正如这里给出的,MyService 没有其他属性,但另一方面,Service 类没有被描述。请提供Short, Self Contained, Correct (Compilable), Example。

标签: c# dependency-injection moq autofixture automoq


【解决方案1】:

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

但是,从AutoFixture 3.20.0 开始,a new auto-mocking customization 就是这样做的——AutoConfiguredMoqCustomization:

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

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

但是有一个问题。作为reported by @dcastro,一个错误是introduced in Moq 4.2.1502.911,它导致只读属性——就像你的例子中的MyService.Logger属性——在AutoFixture配置它们之后被Moq覆盖。

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

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

【讨论】:

  • 感谢 Enrico 的输入,我按照您的建议进行了降级,但仍然得到相同的响应(即 Logger 属性中的空值)。然而,这些问题让我重新考虑了我的代码的结构方式。正如@mark-seemann 在他的博客中指出的那样,如果我不得不设置大量的模拟来测试某些东西,那么我的代码结构可能存在根本性的问题。它并没有改变这样一个事实,即由于某种原因我仍然无法让它为该特定属性设置一个测试替身。
  • 将 Enrico 的答案标记为正确,尽管它没有解决问题,但它指出了可能是原因的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多