Как заглушить IQueryable <t> .Where (Func <t bool>) с помощью Rhino Mocks?</t></t>

Asked
Viewd5198

6

В проекте .net 3.5, над которым я сейчас работаю, я писал несколько тестов для класса обслуживания.

 public class ServiceClass : IServiceClass
{
     private readonly IRepository _repository;

     public ServiceClass(IRepository repository)
     {
          _repository = repository;
     }

     #region IServiceClass Members

     public IEnumerable<ActionType> GetAvailableActions()
     {
         IQueryable<ActionType> actionTypeQuery = _repository.Query<ActionType>();
         return actionTypeQuery.Where(x => x.Name == "debug").AsEnumerable();
     }

     #endregion
}
 

и мне было трудно понять, как заглушить или издеваться над

 actionTypeQuery.Where(x => x.Name == "debug")
 

часть.

Вот что у меня получилось:

 [TestFixture]
public class ServiceClassTester
{
    private ServiceClass _service;
    private IRepository _repository;
    private IQueryable<ActionType> _actionQuery;
    [SetUp]
    public void SetUp()
    {
        _repository = MockRepository.GenerateMock<IRepository>();
        _service = new ServiceClass(_repository);
    }

    [Test]
    public void heres_a_test()
    {
        _actionQuery = MockRepository.GenerateStub<IQueryable<ActionType>>();

        _repository.Expect(x => x.Query<ActionType>()).Return(_actionQuery);
        _actionQuery.Expect(x => x.Where(y => y.Name == "debug")).Return(_actionQuery);

        _service.GetAvailableActions();

        _repository.VerifyAllExpectations();
        _actionQuery.VerifyAllExpectations();
    }

}
 

[Примечание: имена классов были изменены для защиты невиновных]

Но это не удается с System.NullReferenceException в

 _actionQuery.Expect(x => x.Where(y => y.Name == "debug")).Return(_actionQuery);
 

Итак, мой вопрос:

Как издеваться над функцией IQueryable.Where или заглушить ее с помощью RhinoMocks и пройти этот тест?

Если мои текущие настройки не позволяют мне издеваться над IQueryable или заглушать его, дайте аргументированное объяснение почему.

Спасибо, что прочитали этот невероятно длинный вопрос.

  • Оба верхних ответа были достаточно высокого качества, чтобы их можно было выбрать. Спасибо, извини, если я не выбрал твою.

    Mark Rogers27 апреля 2009, 01:55

4 ответов

5

Изначально я хотел смоделировать такие вызовы, как «IQueryable.Where (Func)», но я думаю, что это тестирование на неправильном уровне. Вместо этого в своих тестах я просто издевался над IQueryable, а затем проверял результат:

 // Setup a dummy list that will be filtered, queried, etc
var actionList = new List<ActionType>()
{
    new ActionType() { Name = "debug" },
    new ActionType() { Name = "other" }
};
_repository.Expect(x => x.Query<ActionType>()).Return(actionList);

var result = _service.GetAvailableActions().ToList();

// Check the logic of GetAvailableActions returns the correct subset 
// of actionList, etc:
Assert.That(result.Length, Is.EqualTo(1));
Assert.That(result[0], Is.EqualTo(actionList[0]);

_repository.VerifyAllExpectations();
 
  • Я собирался сказать то же самое на очень похожем примере. Я не обязуюсь. Это очень правильно.

    Как показывает Люк, вам не нужно высмеивать Where (). Это часть вашей логики. Вы проверяете, что лямбда, переданная в Where (), работает правильно. Просто убедитесь, что ваш actionList.Query возвращает данные, которые можно отфильтровать с помощью Where (), и проверьте правильность работы запроса на основе возвращенного набора данных.

    Молодец, Люк.

    Brian Genisio27 апреля 2009, 00:55
6

Where - это метод расширения, это не метод, реализованный интерфейсом IQueriable. Посмотрите на участников IQueriable: http://msdn.microsoft .com / ru-ru / library / system.linq.iqueryable_members.aspx

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

Изменить, пример:

 [TestFixture]
public class ServiceClassTester
{
    private ServiceClass _service;
    private IRepository _repository;
    private IQueryable<ActionType> _actionQuery;

    [SetUp]
    public void SetUp()
    {
        _service = new ServiceClass(_repository);

        // set up the actions. There is probably a more elegant way than this.
        _actionQuery = (new List<ActionType>() { ActionA, ActionB }).AsQueryable();

        // setup the repository
        _repository = MockRepository.GenerateMock<IRepository>();
        _repository.Stub(x => x.Query<ActionType>()).Return(_actionQuery);
    }

    [Test]
    public void heres_a_test()
    {
        // act
        var actions = _service.GetAvailableActions();

        // assert
        Assert.AreEqual(1, actions.Count());
        // more asserts on he result of the tested method
    }

}
 

Примечание: вам не нужно ожидать вызова, потому что ваш метод зависит от возвращаемого значения макета. Если бы он не называл это, он бы потерпел неудачу в утверждениях. Это упрощает сопровождение вашего теста.

6

Без использования mocks Rhino вы можете создать список, а затем вызвать для него .AsQueryable (). например

 var actionTypeList = new List<ActionType>() {
    new ActionType {},  //put your fake data here
    new ActionType {}
};

var actionTypeRepo = actionTypeList.AsQueryable();
 

Это, по крайней мере, даст вам поддельный репозиторий, но не позволит вам проверить, были ли вызваны методы.