Moq.Mock - 如何设置采用表达式的方法
我正在模拟我的存储库接口,并且不确定如何设置一个接受表达式并返回对象的方法?我正在使用 Moq 和 NUnit。
接口:
public interface IReadOnlyRepository : IDisposable
{
IQueryable<T> All<T>() where T : class;
T Single<T>(Expression<Func<T, bool>> expression) where T : class;
}
使用 IQueryable 进行测试已经设置,但不知道如何设置 T Single:
private Moq.Mock<IReadOnlyRepository> _mockRepos;
private AdminController _controller;
[SetUp]
public void SetUp()
{
var allPages = new List<Page>();
for (var i = 0; i < 10; i++)
{
allPages.Add(new Page { Id = i, Title = "Page Title " + i, Slug = "Page-Title-" + i, Content = "Page " + i + " on page content." });
}
_mockRepos = new Moq.Mock<IReadOnlyRepository>();
_mockRepos.Setup(x => x.All<Page>()).Returns(allPages.AsQueryable());
//Not sure what to do here???
_mockRepos.Setup(x => x.Single<Page>()
//----
_controller = new AdminController(_mockRepos.Object);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以这样设置:
但是您遇到了 Moq 的缺点之一。您可能希望在那里放置一个实际的表达式,而不是使用
It.IsAny
,但 Moq 不支持设置采用特定表达式的表达式的方法(这是一个很难实现的功能)。困难在于必须弄清楚两个表达式是否等价。因此,在您的测试中,您可以传入 any
Expression>
,它将传回您设置的模拟要返回的任何内容。测试的价值被稍微稀释了。You can set it up like this:
However you are coming up against one of Moq's shortcomings. You would want to put an actual expression there instead of using
It.IsAny
, but Moq doesn't support setting up methods that take expressions with specific expressions (it's a difficult feature to implement). The difficulty comes from having to figure out whether two expressions are equivalent.So in your test you can pass in any
Expression<Func<Page,bool>>
and it will pass back whatever you have setup the mock to return. The value of the test is a little diluted.让 .Returns 调用返回 allPages 变量的表达式结果。
Have the .Returns call return the result of the expression against your allPages variable.
我发现应使用
It.Is
代替It.IsAny
以获得更准确的结果。I have found that
It.Is<T>
should be used in place ofIt.IsAny<T>
for more accurate results.使用 Moq 的
It.IsAny<>
而不使用.CallBack
会迫使您编写测试未涵盖的代码。相反,它允许任何查询/表达式通过,从单元测试的角度来看,你的模拟基本上毫无用处。解决方案:您要么需要使用回调来测试表达式,要么需要更好地约束您的模拟。无论哪种方式都是混乱且困难的。自从我实践 TDD 以来,我就一直在处理这个问题。我最终组合了一个辅助类,使其更具表现力并且不那么混乱。这是一个可能的最终结果的示例:
这是讨论它并提供源代码的博客文章: http://awkwardcoder.com/2013/04/24/constraining-mocks-with-expression-arguments/
Using Moq's
It.IsAny<>
without a.CallBack
forces you to write code that's not covered by your test. Instead, it allows any query/expression at all to pass through, rendering your mock basically useless from a unit testing perspective.The solution: You either need to use a Callback to test the expression OR you need to constrain your mock better. Either way is messy and difficult. I've dealt with this issue for as long as I've been practicing TDD. I finally threw together a helper class to make this a lot more expressive and less messy. Here's an example of one possible end-result:
Here's the blog article that talks about it and gives the source code: http://awkwardcoder.com/2013/04/24/constraining-mocks-with-expression-arguments/