简体   繁体   English

使用Moq设置并验证表达式

[英]Setup and verify expression with Moq

Is there a way to setup and verify a method call that use an Expression with Moq? 有没有办法设置和验证使用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) 第一次尝试是我想让它工作的那个,而第二次尝试是让Assert部分工作的“补丁”(验证部分仍然失败)

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. Assert测试失败并抛出空引用异常,因为从不调用方法GetByFilter。

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. 测试通过了Assert部分,但这次是验证失败,说它从未被调用过。

Is there a way to setup a method call with a specific expression instead of using a generic It.IsAny<>() ? 有没有办法用特定的表达式设置方法调用,而不是使用泛型It.IsAny<>()

Update 更新

I tried also the suggestion by Ufuk Hacıoğulları in the comments and created the following 我在评论中也尝试了UfukHacıoğulları的建议并创建了以下内容

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM