Как вы заглушаете IQueryable <T>.Where (Func <T, bool>) с Rhino Mocks? - PullRequest
5 голосов
/ 26 апреля 2009

В проекте .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, то дайте мотивированное объяснение, почему.

Спасибо за чтение этого эпически длинного вопроса.

Ответы [ 4 ]

6 голосов
/ 27 апреля 2009

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

Метод расширения является статическим и не может быть смоделирован. ИМО, не надо издеваться над 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 голосов
/ 26 апреля 2009

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

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

var actionTypeRepo = actionTypeList.AsQueryable();

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

5 голосов
/ 27 апреля 2009

Изначально я тоже хотел смоделировать вызовы типа '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();
0 голосов
/ 16 ноября 2012

У меня была похожая проблема, когда я пытался заглушить выражение предиката для Find-метода, который содержит строку, но String, конечно, является ссылочным типом и неизменным. Безуспешно, пока я не создаю testPredicate, который я передаю заглушке, фактическому SUT и, наконец, утверждаю. Ниже код работает.

    [Test()]
    public void Search_Apartment_With_Spesific_Address()
    {
        //ARRANGE
        var repositoryMock = MockRepository.GenerateMock<IApartmentRepository>();
        var notificationMock = MockRepository.GenerateMock<INotificationService>();
        var service = new ApartmentService(repositoryMock, notificationMock);
        var apartment = new List<Apartment> {new Apartment {Address = "Elm Street 2"}}.AsQueryable();

        Expression<Func<Apartment, bool>> testPredicate = a => a.Address == "Elm Street 2";
        repositoryMock.Stub(x => x.Find(testPredicate)).Return(apartment);

        //ACT
        service.Find(testPredicate);

        //ASSERT
        repositoryMock.AssertWasCalled(x => x.Find(testPredicate));
    }
...