【问题标题】:Setup and verify expression with Moq使用 Moq 设置和验证表达式
【发布时间】:2013-07-10 12:33:19
【问题描述】:

有没有办法设置和验证使用带 Moq 的表达式的方法调用?

第一次尝试是我想让它工作的一次尝试,而第二次尝试是让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 测试在 Assert 处失败并抛出空引用异常,因为 GetByFilter 方法从未被调用。

如果我改用这个

[Setup]
public void SetUp()
{
  productsQuery.Setup(x => x.GetByFilter(It.IsAny<Expression<Func<Product, bool>>>())).Returns(new Product() { Title = "Good product", ... });
}

测试通过了 Assert 部分,但这次是 Verify that failed 表示它从未被调用。

有没有办法使用特定表达式而不是使用通用 It.IsAny&lt;&gt;() 来设置方法调用?

更新

我也在 cmets 中尝试了 Ufuk Hacı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());
}

但我得到一个空引用异常,就像第一次尝试一样。

我的控制器中的代码如下

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

【问题讨论】:

  • 您能否将 lambda 表达式分配给一个变量并在 Setup 和 Verify 调用中使用它?
  • 不走运。用您的建议更新问题
  • 我可能误解了您要执行的操作,但如果您只是想验证设置是否匹配,您不能只使用 VerifyAll 吗?
  • 我可以猜到,但无论如何都不会调用设置。
  • 从哪里获得 NRE?

标签: c# moq


【解决方案1】:

以下代码演示了如何在这种情况下进行测试。一般的想法是您对“真实”数据执行传入的查询。这样,你甚至不需要“验证”,如果查询不正确,它就不会找到数据。

根据您的需要进行修改:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-06
    • 2011-10-02
    • 2019-11-16
    • 2023-01-29
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2011-12-20
    相关资源
    最近更新 更多