Setup and verify expression with Moq
c#, moq
Solution
The following code demonstrates how to test in such scenarios. The general idea is that you execute the passed in query against a "real" data. That way, you don't even need "Verify", as if the query is not right, it will not find the data.
Modify to suit your needs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Moq;
using NUnit.Framework;
namespace StackOverflowExample.Moq
{
public class Product
{
public string UrlRewrite { get; set; }
public string Title { get; set; }
}
public interface IProductQuery
{
Product GetByFilter(Expression<Func<Product, bool>> filter);
}
public class Controller
{
private readonly IProductQuery _queryProvider;
public Controller(IProductQuery queryProvider)
{
_queryProvider = queryProvider;
}
public Product GetProductByUrl(string urlRewrite)
{
return _queryProvider.GetByFilter(x => x.UrlRewrite == urlRewrite);
}
}
[TestFixture]
public class ExpressionMatching
{
[Test]
public void MatchTest()
{
//arrange
const string GOODURL = "goodurl";
var goodProduct = new Product {UrlRewrite = GOODURL};
var products = new List<Product>
{
goodProduct
};
var qp = new Mock<IProductQuery>();
qp.Setup(q => q.GetByFilter(It.IsAny<Expression<Func<Product, bool>>>()))
.Returns<Expression<Func<Product, bool>>>(q =>
{
var query = q.Compile();
return products.First(query);
});
var testController = new Controller(qp.Object);
//act
var foundProduct = testController.GetProductByUrl(GOODURL);
//assert
Assert.AreSame(foundProduct, goodProduct);
}
}
}
Problem
Is there a way to setup and verify a method call that use an Expression with Moq? The first attempt is the one I would like to get it to work, while the second one is a "patch" to let the `Assert` part works (with the verify part still failing) ``` string goodUrl = "good-product-url"; [Setup] public void SetUp() { productsQuery.Setup(x => x.GetByFilter(m=>m.Url== goodUrl).Returns(new Product() { Title = "Good product", ... }); } [Test] public void MyTest() { var controller = GetController(); var result = ((ViewResult)controller.Detail(goodUrl)).Model as ProductViewModel; Assert.AreEqual("Good product", result.Title); productsQuery.Verify(x => x.GetByFilter(t => t.Url == goodUrl), Times.Once()); } ``` Thet test fail at the `Assert` and throw a null reference exception, because the method GetByFilter is never called. If instead I use this ``` [Setup] public void SetUp() { productsQuery.Setup(x => x.GetByFilter(It.IsAny<Expression<Func<Product, bool>>>())).Returns(new Product() { Title = "Good product", ... }); } ``` The test pass the Assert part, but this time is the Verify that fail saying that it is never called. Is there a way to setup a method call with a specific expression instead of using a generic `It.IsAny<>()`? Update I tried also the suggestion by Ufuk Hacıoğulları in the comments and created the following ``` Expression<Func<Product, bool>> goodUrlExpression = x => x.UrlRewrite == "GoodUrl"; [Setup] public void SetUp() { productsQuery.Setup(x => x.GetByFilter(goodUrlExpression)).Returns(new Product() { Title = "Good product", ... }); } [Test] public void MyTest() { ... productsQuery.Verify(x => x.GetByFilter(goodUrlExpression), Times.Once()); } ``` But I get a null reference exception, as in the first attempt. The code in my controller is as follow ``` public ActionResult Detail(string urlRewrite) { //Here, during tests, I get the null reference exception var entity = productQueries.GetByFilter(x => x.UrlRewrite == urlRewrite); var model = new ProductDetailViewModel() { UrlRewrite = entity.UrlRewrite, Culture = entity.Culture, Title = entity.Title }; return View(model); } ```