AutoFixture+Moq - замораживание ложного класса, препятствующего настройке

Я хотел бы понять, почему мой тест не проходит, когда я замораживаю смоделированный класс вместо смоделированного интерфейса

[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;
    }
}

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

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

Моя версия автофиксации: 3.6.5.0

1 ответ

Решение

MyWebRequest является конкретным (неабстрактным) классом, и AutoFixture.AutoMoq не создает те, которые используют Moq. Это сделано специально, поскольку ядро AutoFixture уже занимается созданием "нормальных" классов.

Вы можете изменить это поведение, если хотите. Часто, однако, я бы подумал о том, чтобы сделать это дизайнерским запахом. Однако в этом случае трудно сказать, потому что вы хорошо поработали над уменьшением проблемы до минимального повторения. Проблема в том, что, как представлено здесь, MyService не добавляет никакой ценности. Я уверен, что это не то, как выглядит ваш реальный код, но, поскольку я не могу догадаться, как выглядит ваш реальный код, я не могу сказать, возможен ли лучший дизайн.

Другие вопросы по тегам