Moq с лямбда-выражениями?

Я пытаюсь протестировать службу приложений, используя Moq 4.0.10827 (на NuGet), и мне нужно запросить репозиторий:

public class MyService
{
    Repository<MyObject> _Repo;

    public MyObject Get (string SomeConstraint)
    {
        return _Repo
            .GetTheFirstOneOrReturnNull (M => M.Constraint.Equals (
                SomeContraint, StringComparison.InvariantCultureIgnoreCase
            ));  // GetTheFirstOneOrReturnNull takes a Func<MyObject, bool>
    }
}

Как воспроизвести лямбда-выражение с помощью Moq? Я продолжаю получать исключение «Неподдерживаемое выражение».

Вот идея того, что я уже делаю:

[TestMethod]
public void GetByMyConstraintShouldReturnWithMyObject ()
{
    // Arrange
    const string MyConstraint = "Constraint";
    MyObject Expected = new MyObject { Constraint = MyConstraint };
    Mock<Repository<MyObject>> MockRepo = new Mock<Repository<MyObject>> ();
    MockRepo.Setup (x => x.GetTheFirstOneOrReturnNull (M => M.Constraint.Equals (MyConstraint, StringComparison.InvariantCultureIgnoreCase)))
            .Returns (Expected).Verifable ();
    MyService Service = new MyService (MockRepo.Object);

    // Act
    MyObject Result = Service.Get (MyConstraint);


    // Assert
    Assert.AreSame (Expected, Result);
    MockRepo.Verify ();

}

Я просмотрел некоторые другие ответы, но я не могу понять, что я делаю неправильно (по общему признанию, «нуб» с Moq). Я пришел к выводу, что это будет больно, но у меня впереди много подобных тестов, и я хочу стать твердым сейчас, а не тонуть позже.

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


person Jim D'Angelo    schedule 10.06.2011    source источник


Ответы (3)


Это не должно требовать много испытаний. Один правильный тест покажет, что код, делегирующий FirstOrDefault, работает, тогда все последующие тесты действительно проверяют правильность логики в ограничении Func, что можно сделать, не передавая его в Repository.

person Luke Puplett    schedule 10.06.2011
comment
Хм... Возможно, мой вопрос не отражает то, что я действительно пытаюсь проверить. Я могу небрежно относиться к репо, поэтому я издеваюсь над ним. Я просто хочу проверить сервис. Для этого я использовал нестандартную заглушку вместо Moq. Похоже, он не очень хорошо справляется с Func‹T, TResult›. - person Jim D'Angelo; 10.06.2011

Похоже, вы пытаетесь издеваться над методами расширения. Вы не можете имитировать методы расширения таким образом, потому что они на самом деле не объявлены для типа, который вы имитируете.

В этом случае, поскольку ваш репозиторий, похоже, представляет собой набор вещей, вы должны вместо этого заменить простую жестко запрограммированную коллекцию. Непонятно, как именно вы можете это сделать, поскольку вы не предоставили исходный код для IRepository.

person marcind    schedule 10.06.2011
comment
Я не уверен, как здесь поможет добавление репозитория. В данном случае он просто возвращает первое или значение по умолчанию из любого резервного хранилища (в памяти или в базе данных, не имеет значения). FirstOrDefault — это просто имя метода, которое я дал ему в своем примере — на самом деле оно определяется классом репозитория и принимает Func‹T, bool›. - person Jim D'Angelo; 10.06.2011

Я бы сказал, что лучше всего обновить ваш Repository, чтобы он имел что-то вроде метода FindByConstraint, где все, что вы передаете, это Constraint, а само репо выполняет FirstOrDefault(). Я думаю, что для этого есть разумные конструктивные причины, а также просто упростить тестирование - поиск выполняется без учета регистра и с радостью возвращает нуль, что вы можете рассматривать как решения, которые должен принимать репо, а не его клиенты. .

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

person Steve Wilkes    schedule 10.06.2011
comment
Полностью согласен с вашим последним утверждением. У меня есть планы провести рефакторинг и сделать репозиторий более дружелюбным, это просто то, с чем я столкнулся, когда тестировал что-то, что требует Func‹T, bool›, и я хотел знать, сможет ли Moq хорошо с ним работать. - person Jim D'Angelo; 10.06.2011