AutoFixture + Moq-冻结模拟类以防止设置

Joh*_*ohn 5 c# unit-testing moq autofixture

我想了解为什么冻结冻结的模拟类而不是模拟的接口时测试失败

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

    var webRequestMock = fixture.Freeze<Mock<MyWebRequest>>(); // freezing a class + setuping a return value
    webRequestMock.Setup(a => a.GetData())
    .Returns("Foo");

    var myService = fixture.Create<MyService>();

    var actual = myService.GetData();

    webRequestMock.Verify(a => a.GetData(), Times.Once()); // Failed it's never called once
    Assert.Equal("Foo", actual); // Failed, if we comment previous line, 'actual' value is always empty
}

public class MyService
{
    private readonly MyWebRequest _request;

    public MyService(MyWebRequest request)
    {
        _request = request;
    }

    public string GetData()
    {
        var data = _request.GetData();
        return data;
    }
}

public class MyWebRequest 
{
    public virtual string GetData() // you can see here, the method is well virtual, and should be overridable by moq.
    {
        return string.Empty;
    }
}
Run Code Online (Sandbox Code Playgroud)

1 /如果我尝试使用模拟接口,则可以使用。

[Fact]
public void MethodeName()
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    const string expected = "Foo";

    var webRequestMock = fixture.Freeze<Mock<IMyWebRequest>>();
    webRequestMock.Setup(a => a.GetData())
    .Returns("Foo");

    var myService = fixture.Create<MyService>();

    var actual = myService.GetData();

    webRequestMock.Verify(a => a.GetData(), Times.Once()); // Success
    Assert.Equal(expected, actual); // Success
}

public class MyService
{
    private readonly IMyWebRequest _request;

    public MyService(IMyWebRequest request)
    {
        _request = request;
    }

    public string GetData()
    {
        var data = _request.GetData();
        return data;
    }
}

public interface IMyWebRequest
{
    string GetData();
}

public class MyWebRequest : IMyWebRequest
{
    public virtual string GetData()
    {
        return string.Empty;
    }
}
Run Code Online (Sandbox Code Playgroud)

2 /如果我使用“注入”而不是冻结,则可以使用:

[Fact]
public void MethodeName()
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    const string expected = "Foo";

    var webRequestMock = new Mock<MyWebRequest>(); 
    webRequestMock.Setup(a => a.GetData()).Returns("Foo");
    fixture.Inject(webRequestMock.Object);

    var myService = fixture.Create<MyService>();

    var actual = myService.GetData();

    webRequestMock.Verify(a => a.GetData(), Times.Once()); // Success
    Assert.Equal(expected, actual); // Success
}

public class MyService
{
    private readonly MyWebRequest _request;

    public MyService(MyWebRequest request)
    {
        _request = request;
    }

    public string GetData()
    {
        var data = _request.GetData();
        return data;
    }
}

public class MyWebRequest 
{
    public virtual string GetData()
    {
        // make WebRequest
        return string.Empty;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的自动治具版本:3.6.5.0

Mar*_*ann 5

MyWebRequest是一个具体的(非抽象)类,而AutoFixture.AutoMoq不会使用Moq创建那些类。这是设计使然,因为AutoFixture内核已经处理了“普通”类的创建。

如果您愿意,可以更改此行为。不过,我经常会考虑把这当成一种设计味道。但是,在这种情况下很难说,因为您在将问题减少到最小重现方面做得很好。但是,这里的问题在于,正如此处介绍的那样,MyService并没有增加任何价值。我敢肯定这不是您真实代码的样子,但由于我无法猜测您的真实代码是什么样子,因此我不知道是否有更好的设计。