使用Moq设置并验证表达式
本文关键字:验证 表达式 设置 Moq 使用 | 更新日期: 2023-09-27 18:21:59
有没有办法设置和验证使用带Moq的Expression的方法调用?
第一次尝试是我想让它工作的,而第二次尝试是一个"补丁",让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());
}
由于从未调用方法GetByFilter,因此在Assert
测试失败并引发null引用异常。
如果我使用这个
[Setup]
public void SetUp()
{
productsQuery.Setup(x => x.GetByFilter(It.IsAny<Expression<Func<Product, bool>>>())).Returns(new Product() { Title = "Good product", ... });
}
测试通过了Assert部分,但这一次是Verify失败,表明它从未被调用。
有没有一种方法可以用特定的表达式来设置方法调用,而不是使用通用的It.IsAny<>()
?
更新
我也尝试了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);
}
下面的代码演示了如何在这样的场景中进行测试。一般的想法是对"真实"数据执行传入的查询。这样,您甚至不需要"验证",因为如果查询不正确,它将找不到数据。
修改以满足您的需求:
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);
}
}
}