Как вернуть значение, отличное от заглушки, на основе лямбда-аргумента - PullRequest
1 голос
/ 03 января 2012

У меня есть следующий пример тестового кода

    public Stage Test(Stage Stage)
    {
        var StartStage = StageRepository.Single(x => x.Order == 1);
        var EndStage = StageRepository.Single(x => x.Order == 5);
        var ErrorStage = StageRepository.Single(x => x.Name == "Error");

        if (Stage == StartStage)
        {
            return EndStage;
        }
        else
        {
            return ErrorStage;
        }
    }

И я пытаюсь проверить его с помощью следующего модульного теста

    [TestMethod]
    public void XXXTest()
    {
        //// Arrange
        var AutoMocker = new RhinoAutoMocker<StageService>(MockMode.AAA);

        MockRepository mockRepository = new MockRepository();

        var MockStageRepository = AutoMocker.Get<IRepository<Stage>>();

        Stage StartStage = mockRepository.Stub<Stage>();
        StartStage.Order = 1;

        Stage EndStage = mockRepository.Stub<Stage>();
        EndStage.Order = 5;

        Stage ErrorStage = mockRepository.Stub<Stage>();
        ErrorStage.Name = "Error";

        System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> StartParam = x => x.Order == 1;
        MockStageRepository
            .Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(StartParam)))
            .Return(StartStage);

        System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> EndParam = x => x.Order == 1;
        MockStageRepository
            .Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(EndParam)))
            .Return(EndStage);

        System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> ErrorParam = x => x.Order == 1;
        MockStageRepository
            .Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(ErrorParam)))
            .Return(ErrorStage);

        StageService StageService = AutoMocker.ClassUnderTest;


        //Act
        var ReturnStage = StageService.Test(StartStage);


        //Assert
        Assert.AreEqual(ReturnStage, EndStage);
    }

Однако это не работает, так как не возвращаетсяничего, когда я вызываю StageRepository.Single ().Если я изменяю код заглушки, чтобы игнорировать аргумент, он возвращает что-то, но это будет один и тот же объект, возвращаемый для каждого вызова Single (), который мне не нужен.

Можно ли настроить RhinoMocks втаким образом, чтобы вернуть разные объекты из заглушки в зависимости от того, какая лямбда передана в него?

Ответы [ 3 ]

2 голосов
/ 03 января 2012

Я думаю, что корень вашей проблемы в том, что равенство для типа Expression<Func<T,U>> выполняется по ссылке, а не по значению.Это означает, что вы приказываете Rhino Mocks искать экземпляры выражений, созданных в тесте, а не созданные в коде, который вы тестируете.

На ум приходят два возможных подхода:

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

    Может быть что-то вроде:

    internal void SetStartStage(Expression<Func<Entities.Stage,bool>> predicate)
    {
        ...
    }
    

    Обратное это также сработает, т. Е. Предоставьте объекты Expression как поля / свойства, к которым вы можете получить доступ при тестировании, а затемиспользуйте их при настройке макета:

    internal Expression<Func<Entities.State,bool>> StartStagePredicate
    {
        get{ return x => x.Order == 1; }
    }
    
  • Другой вариант - использовать метод Matches для Args, чтобы проверить, проверяет ли аргумент состояние объекта Stageправильно.Для этого потребуется создать в вашем тесте несколько Stage объектов, которые будут соответствовать критериям:

    var startStageTester = new Stage { Order = 1 };
    MockStageRepository
            .Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Matches(y => y.Compile()(startStageTester)))
            .Return(StartStage);
    

    Вызов Compile() немного раздражает, но поскольку вы имеете дело с выражением, а не спрямая лямбда, вы должны скомпилировать ее, чтобы оценить.

    Теперь, если Stage - это то, что трудно создать, тогда вам может понадобиться создать Mock / Stub изодин (или вы используете StartStage), и он возвращает 1 из свойства Order (в любом случае в случае StartStage).

Возможно, есть некоторые другие, которые яя тоже не думаю сейчас.

1 голос
/ 14 февраля 2013

ЕСЛИ условие linq не важно, я бы предложил сопоставить его как любое, что-то вроде этого

repository.Stub(x => x.Find(Arg<System.Linq.Expressions.Expression<Func<Entity, bool>>>.Is.Anything)).Return(entitiesList.AsQueryable());

Надеюсь, эта помощь.

0 голосов
/ 04 января 2012

Спасибо за это.Это сработало.Единственное, чего мне не хватало, - это метода Compile в ExpressionTree.В вашем примере кода есть небольшая ошибка (вы используете x дважды).Для полноты вот рабочий код.

        MockStageRepository2
            .Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Matches(y => y.Compile()(StartStage2))))
            .Return(StartStage2);
...