Question

I use a generic repository to access data in C#, the method signature of which is this:

public virtual IEnumerable<TEntity> Get(
    Expression<Func<TEntity, bool>> filter = null,
    Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
    string includeProperties = "")

this is then used in an MVC controller (for example) in the following ways

var users = UnitOfWork.UserRepository.Get(
    u => u.Id == userId, null, "CreatedEmployer,CreatedEmployer.CreatedByUser");

var checkUser = UnitOfWork.UserRepository.Get(u => u.UserName == email)
                                         .FirstOrDefault();

I want to be able to mock these calls using RhinoMocks and receive specific results based on the expression that was called. The pseudo code below demonstrates what I want to achieve e.g.

UnitOfWork.UserRepository.Expect(
    u => u.Get(Arg<Expression<Func<User, bool>>>.Matches(u.UserName == "jim")))
                         .Return(new List<User>() { userJim });

UnitOfWork.UserRepository.Expect(
    u => u.Get(Arg<Expression<Func<User, bool>>>.Matches(u.UserName == "jo left ages ago")))
                         .Return(new List<User>() );

I have tried using .WhenCalled but it does not seem to have the behaviour I want which is when matching a provided an exact provided expression, return some specific data:

.WhenCalled(invocation => {
    var predicate = invocation.Arguments.First() as Expression<Func<User, bool>>;
    ... Do something here
})

I've been trawling the internet for a while on this but have not managed to dig up a decent solution, most of the solutions consist of ignoring the arguments which works so long as you only call the repo once in a method e.g.

UserRepository.Expect(u => u.Get()).IgnoreArguments()
              .Return(new List<User> { CurrentUser });

This has now proved inadequate and I need something a bit more robust and specific. I am only really interested in the first argument. I need a solution to the above but if a solution does not exist for RhinoMocks then I'd be interested in any mocking framework where testing expressions was easier to achieve.

Était-ce utile?

La solution 2

Here is an adaptation of the solution proposed by Sunny. Thanks for his advice and the steer to the solution for RhinoMocks.

For all tests you have an object called which is all the data that might ever be returned from any of your calls to the repository. In my case this is the users data set:

List<User> users = new List<User>();

Then at each arrange you add new users

users.Add(new User() { username="jim" });
users.Add(new User() { username="jo left ages ago" });

Then you call once to Expect. This sets up any call to the repo to query the data you have provided. For some reason this does not work with two calls to expect. To Rhino Mocks it only appears as if one call has been made:

baseController.UnitOfWork.UserRepository.Expect(u => u.Get(Arg<Expression<Func<User, bool>>>.Is.Anything, Arg<Func<IQueryable<User>, IOrderedQueryable<User>>>.Is.Anything, Arg<string>.Is.Anything))
    .WhenCalled(invocation =>
        {
        var predicate = invocation.Arguments.First() as Expression<Func<User, bool>>;
        var query = predicate.Compile();
        invocation.ReturnValue = users.Where(query);
        });

As an aside, it still doesn't fit nicely with the way calls to SpecFlow's Given statements setup the expectations. What natural statement do you associate with setting up the Expect? But it does answer my original question.

Autres conseils

I have answered similar question using Moq. You can use the same approach with Rhino.

The key is to use a real (or mocked) data set, and run the expressions against it.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top