Модульное тестирование шаблона Builder с Moq

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

Не уверен, является ли это ограничением Moq или моим собственным ограничением и невежеством.

Вот так выглядит мой контроллер:

public class OutletController : Controller
{
    private readonly IOutletViewModelBuilder _builder;

    public OutletController(IOutletViewModelBuilder builder)
    {
        this._builder = builder;
    }


    public ActionResult Edit(int id)
    {
        OutletViewModel viewModel = this._builder.WithOutlet(id).WithCountryList().Build();

        return View(viewModel);
    }
}

Я пытаюсь смоделировать объект IOutletViewModelBuilder, но получаю следующее:

[Test]
public void DummyTest()
{
    Mock<IOutletViewModelBuilder> mockBuilder = new Mock<IOutletViewModelBuilder>();
    // (1) // mockBuilder.Setup(m => m.WithOutlet(It.IsAny<int>())).Returns(mockBuilder.Object);
    // (2) //mockBuilder.Setup(m => m.WithOutlet(It.IsAny<int>())).Returns(mockBuilder);

    // (3) // mockBuilder.Setup(m => m.WithOutlet(It.IsAny<int>()).WithCountryList().Build()).Returns(new OutletViewModel());

    OutletController controller = new OutletController(mockBuilder.Object);
    ActionResult result = controller.Edit(1);

    Assert.IsTrue(true);
}

(1) выдает следующее выделение ошибки (mockBuilder.Object)

Не удается разрешить метод «Возвраты (ViewModelBuilders.Builders.IOutletViewModelBuilder)», кандидатами являются:

Moq.Language.Flow.IReturnsResult<ViewModelBuilders.Builders.IOutletViewModelBuilder> Returns(System.Func<ViewModelBuilders.Builder.IOutletViewModelBuilder>) (in interface IReturns<IOutletViewModelBuilder,OutletViewModelBuilder>)
Moq.Language.Flow.IReturnsResult<ViewModelBuilders.Builders.IOutletViewModelBuilder> Returns(ViewModelBuilders.Builders.OutletViewModelBuilder) (in interface IReturns<IOutletViewModelBuilder,OutletModelBuilder>)

(2) выдает следующую ошибку:

Не удается разрешить метод «Возвраты (Moq.Mock)», кандидатами являются:

Moq.Language.Flow.IReturnsResult<ViewModelBuilders.Builders.IOutletViewModelBuilder> Returns(System.Func<ViewModelBuilders.Builders.OutletViewModelBuilder>) (in interface IReturns<IOutletViewModelBuilder,OutletViewModelBuilder>)
Moq.Language.Flow.IReturnsResult<ViewModelBuilders.Builders.IOutletViewModelBuilder> Returns(ViewModelBuilders.Builders.OutletViewModelBuilder) (in interface IReturns<IOutletViewModelBuilder,OutletViewModelBuilder>)

(3) выдает ошибку не во время компиляции, а во время выполнения:

System.NotSupportedException : Invalid setup on a non-virtual (overridable in VB) member: m => m.WithOutlet(It.IsAny<Int32>()).WithCountryList().Build()
at Moq.Mock.ThrowIfCantOverride(Expression setup, MethodInfo method)
at Moq.Mock.<>c__DisplayClass1c`2.<Setup>b__1b()
at Moq.Mock.Setup(Mock mock, Expression`1 expression, Func`1 condition)
at ViewModelBuilderTests.OutletControllerTest.DummyTest() 

Любая помощь будет принята с благодарностью. Модульное тестирование этого метода не должно быть таким сложным, не так ли?

Ниже вы можете увидеть объект Builder на случай, если вам нужно увидеть реализацию.

public class OutletViewModelBuilder
{
    private readonly IRepository _repository;
    private OutletViewModel _viewModel;

    public OutletViewModelBuilder(IRepository repository)
    {
        this._repository = repository;
        this._viewModel = new OutletViewModel();
    }

    public OutletViewModel Build()
    {
        return this._viewModel;
    }

    public OutletViewModelBuilder WithOutlet(int outletId)
    {
        this._viewModel.Outlet = this._repository.GetOutletById(outletId);

        return this;
    }

    public OutletViewModelBuilder WithCountryList()
    {
        this._viewModel.CountryList = this._repository.GetCountryList();

        return this;
    }
}

Наконец, интерфейс IOutletViewModelBuilder

public interface IOutletViewModelBuilder
{
    OutletViewModel Build();

    OutletViewModelBuilder WithOutlet(int outletId);

    OutletViewModelBuilder WithCountryList();
}

person Yag    schedule 27.06.2011    source источник
comment
В случае, если вопрос не ясен. Как я могу заказать объект OutletViewModelBuilder? Должен ли я изменить насмешливую структуру?   -  person Yag    schedule 27.06.2011
comment
Не могли бы вы опубликовать код IOutletViewModelBuilder, над которым вы хотите издеваться?   -  person froeschli    schedule 27.06.2011


Ответы (1)


Похоже, основная проблема заключается в том, что ваши методы WithOutlet и WithCountryList возвращают конкретный OutletViewModelBuilder вместо возврата IOutletViewModelBuilder. Я думаю, вам понадобится что-то вроде этого:

public interface IOutletViewModelBuilder
{
    OutletViewModel Build();
    IOutletViewModelBuilder WithOutlet(int outletId);
    IOutletViewModelBuilder WithCountryList();
}

тогда ваши издевательства:

var myViewModel = TheOutletViewModelForTesting();
var mockBuilder = new Mock<IOutletViewModelBuilder>();

mockBuilder.Setup(m => m.WithOutlet(It.IsAny<int>())).Returns(mockBuilder.Object);
mockBuilder.Setup(m => m.WithCountryList()).Returns(mockBuilder.Object);
mockBuilder.Setup(m => m.Build()).Returns(myViewModel);

// rest of your test that validates that myViewModel is passed correctly to your view
person Brian Geihsler    schedule 27.06.2011
comment
Вот и все! Спасибо, Брайан, это почти смущает. Очень ценю! Так получилось, что проблема была во мне. :-) - person Yag; 27.06.2011