1

How do I mock something that is - Expression> using Moq?

I'm trying to mock a call to my repo layer that takes in a LINQ Expression for constructing a query. I'm trying the below syntax but it fails. The SearchFor method doesn't get called.

var array = new Employee[1];

array[0] = new Employee() { ID = 1234, Name = "Test" };

MockEmployeeRepo.Setup(x => x.SearchFor(It.IsAny<Expression<Func<Employee, bool>>>()))
            .Returns(array.AsQueryable);

var list = EmployeeService.GetEmployees("Test");

MockEmployeeRepo.Verify(x => x.SearchFor(x1 => x1.Name == "Test"), Times.Once());

Assert.AreEqual("Test", list[0].Name);

Here the GetEmployees method looks like below.

public IEnumerable<Employee> GetEmployees(string name)
{
    return repo.SearchFor(x => x.Name == name);
}
govin
  • 6,445
  • 5
  • 43
  • 56
  • As far as I know, you cannot verify expressions, What is SearchFor parameters taking? Is it an expression? – 123 456 789 0 Sep 10 '13 at 15:34
  • Correct. Its taking an expression. Any thoughts on how I would go about unit testing those? – govin Sep 10 '13 at 15:42
  • Do you really need it to be an expression? Why you can't just pass in a string instead of an expression? – 123 456 789 0 Sep 10 '13 at 15:54
  • Because I believe, the SearchFor should just delegate it to the repository, and it will end up in the DbSet you can verify that given the name, it returned the correct results. At this level, I believe you can just verify that it called it. – 123 456 789 0 Sep 10 '13 at 15:55
  • I could do that but I'm trying to make the SearchFor method on my repository very generic so that it can act on any entity. Makes sense? – govin Sep 10 '13 at 22:27
  • But are you injecting this mock repo into your EmployeeService? I don't see that in the above test... – Stephen Byrne Sep 10 '13 at 22:48
  • Correct, I'm injecting a MockEmployeeRepo through the constructor. I didn't include that in the pasted code. – govin Sep 10 '13 at 23:33
  • AFAIK, you can't verify with expressions. – 123 456 789 0 Sep 11 '13 at 01:41
  • possible duplicate of [Setup and verify expression with Moq](http://stackoverflow.com/questions/17570761/setup-and-verify-expression-with-moq) – Sunny Milenov Sep 16 '13 at 23:50

2 Answers2

1

Moq does not supports with Expression function so here is the best solution. Use this nuget package Moq.Expression

// import namespace
using MoqExpression;

// it will work
MockEmployeeRepo.Setup(x => x.SearchFor(MoqHelper.IsExpression<Employee>(s => s.Name.Equals("Test")))).Returns(array.AsQueryable);

For more documentation: https://github.com/ovaishanif94/Moq.Expression

  • As of Oct 10, 2019 Moq.Expression only works for .Net Core. If anyone knows of a solution for .Net 4.7 (or any non .Net Core version) please reply. – schwechel Oct 10 '19 at 20:44
  • @schwechel you can try like below. .Setup(x => x.SearchFor(It.Is>>(e => e.Body.ToString().Contains("x.Name")))).ReturnsAsync(array.AsQueryable) – PradipB Apr 11 '20 at 20:20
0

In some cases you might be able to evaluate the expression into something comparable, like a string.

It.Is<Expression<Func<Employee, bool>>>(expression => SomeEvaluator.Evaluate (expression) == "Name = 'Test'");

In my case I wanted to mock queries to Azure Tables, so I used Azure.Data.Tables.TableClient.CreateQueryFilter for evaluation, i.e.:

It.Is<Expression<Func<TableEntity, bool>>> (query => TableClient.CreateQueryFilter (query) == "RowKey eq 'someId'")
Karlas
  • 981
  • 6
  • 5