Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you stub IQueryable<T>.Where(Func<T, bool>) with Rhino Mocks?

In the .net 3.5 project that I am working on right now, I was writing some tests for a service class.

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
}

and I was having a hard time figuring out how to stub or mock the

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

part.

Here's what I got so far:

[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();
    }

}

[Note: class names have been changed to protect the innocent]

But this fails with a System.NullReferenceException at

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

So my question is:

How do I mock or stub the IQueryable.Where function with RhinoMocks and get this test to pass?

If my current setup won't allow me to mock or stub IQueryable, then give a reasoned explanation why.

Thanks for reading this epically long question.

like image 647
Mark Rogers Avatar asked Apr 26 '09 17:04

Mark Rogers


2 Answers

Without using Rhino mocks, you can create a List and then call .AsQueryable() on it. e.g.

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

var actionTypeRepo = actionTypeList.AsQueryable();

That will at least get you a fake repository, but it won't let you verify that methods were called.

like image 138
Lance Fisher Avatar answered Nov 15 '22 10:11

Lance Fisher


Where is an extension method, this is not a method implemented by the interface IQueriable. Look at the members of IQueriable: http://msdn.microsoft.com/en-us/library/system.linq.iqueryable_members.aspx

An extension method is static and can't be mocked. IMO, there is no need to mock Where, because it's part of the language. You should only mock the repository.

Edit, Example:

[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
    }

}

Note: you don't need to expect the call, because your method depends on the return value of the mock. If it wouldn't call it, it would fail on the asserts. This makes your test easier to maintain.

like image 40
Stefan Steinegger Avatar answered Nov 15 '22 10:11

Stefan Steinegger