我如何阅读这些最小起订量设置表达式?
How do I read these moq setup expressions?
备用标题:这些表达是什么意思?
编辑:This post 几乎有所帮助,但只是解释了两个设置函数之间的区别,而不是如何阅读它们。
我正在学习如何使用最小起订量并为我的团队进行基础培训,在完成 this video and looking up (以及其他)之后,我认为我已经足够了解它,可以使用它了,但仅在 "this is just the way it's done" 的意义上。我没有理由或能力解释语法。请帮忙。
郑重声明,我了解单独使用 C# 模板、表达式、函数、操作和事件,但将它们混在一起?元是真实的。
考虑视频演示单元测试之一的以下代码片段,Should_Mock_Events_Based_On_Action()
(unit test source, IRepo source):
var mockRepo = new Mock<IRepo>();
mockRepo.Setup(x => x.AddRecord(null))
.Raises(m => m.FailedDatabaseRequest += null, this, EventArgs.Empty);
Setup(...)
函数好像读作,"Set up a function that takes an IRepo
and then calls AddRecord(...)
with null
."但是这个setup是mocking up IRepo.AddRecord(...)
,不是表达式。不知何故,这在模拟内部被翻译为 "Set up a function for IRepo
called AddRecord(...)
such that, when it takes null
, it behaves a certain way." 但它不是那样读的。 这应该怎么读?不知何故表达式在某处变成了实际的函数调用。
Raises(...)
这个函数真让我费解。它看起来像是在说,"The previously set up function raises an event that takes an IRepo
and adds null
to its event handler." 并且...不知何故这让事件发生了? += null
操作没有 return 任何东西,我一直无法弄清楚如何将其理解为该处理程序正在寻找的事件。我发现许多文章和 SO 帖子表明这就是它是如何完成的,但是其中 none(我已经找到)解释了 为什么 。 这应该怎么读?
假设我有一个接口 ITest
只有一个方法:
public interface ITest
{
bool IsEvent(int input);
}
然后我想模拟这个 - 请记住,现在我 没有 实际具体 class.
var mock = new Mock<ITest>();
现在我想设置 2 个电话:
mock.Setup(x => x.IsEven(1)).Returns(false);
mock.Setup(x => x.IsEven(2)).Returns(true);
这是对模拟对象说的:
If your method IsEven gets called with a value of 1 then return false.
If your method IsEven gets called with a value of 2 then return true.
您正在设置模拟对象的行为。
所以如果我在代码中这样做:
var for1 = mock.Object.IsEven(1);
var for2 = mock.Object.IsEven(2);
变量 for1
将为假而 for2
将为真,因为我告诉模拟对象它应该做什么。 Setup
的参数实际上表示 "This is the behaviour I want you to look out for and I will then tell you what to do"。在我的例子中,我使用 Returns
方法来指定在特定情况下从我的模拟对象实际返回的内容。
在您的具体情况下:
mockRepo.Setup(x => x.AddRecord(null))
.Raises(m => m.FailedDatabaseRequest += null, this, EventArgs.Empty);
这是对模拟对象说的
If someone calls the AddRecord method with a parameter of null then
raise an event of type FailedDatabaseRequest
有关 Raises
方法的更多信息,请查看此处的 Moq quickstart documentation for events。
有关使用 Moq 引发事件的更深入的视图,有一些有用的信息 here - 特别是它讨论了让您有些困惑的 += null
:
To raise an event from a mock object we use its Raise method. This
accepts two parameters. The first is a lambda expression that includes
an empty event subscriber for the event to raise. Although not the
most elegant syntax, this is required to allow Moq to understand how
the event is used. The second parameter provides the event arguments
that will be included with the event.
回答自己的问题。
我的困惑源于不理解 C# 表达式的工作原理(不是 lambda 表达式,而是具体 Expression<>
)。它们暴露了编译器理论(特别是 "expression trees"),可用于将 lambda 解构为多个部分,包括参数、常量、二元运算符等。 Moq利用了这一点,并使用这些片段来构造自己的具有指定功能的对象+支持代码以进行验证。我不知道 C# 可以做到这一点。
解惑的系列教程:C# Expression Trees
备用标题:这些表达是什么意思?
编辑:This post 几乎有所帮助,但只是解释了两个设置函数之间的区别,而不是如何阅读它们。
我正在学习如何使用最小起订量并为我的团队进行基础培训,在完成 this video and looking up
郑重声明,我了解单独使用 C# 模板、表达式、函数、操作和事件,但将它们混在一起?元是真实的。
考虑视频演示单元测试之一的以下代码片段,Should_Mock_Events_Based_On_Action()
(unit test source, IRepo source):
var mockRepo = new Mock<IRepo>();
mockRepo.Setup(x => x.AddRecord(null))
.Raises(m => m.FailedDatabaseRequest += null, this, EventArgs.Empty);
Setup(...)
函数好像读作,"Set up a function that takes anIRepo
and then callsAddRecord(...)
withnull
."但是这个setup是mocking upIRepo.AddRecord(...)
,不是表达式。不知何故,这在模拟内部被翻译为 "Set up a function forIRepo
calledAddRecord(...)
such that, when it takesnull
, it behaves a certain way." 但它不是那样读的。 这应该怎么读?不知何故表达式在某处变成了实际的函数调用。Raises(...)
这个函数真让我费解。它看起来像是在说,"The previously set up function raises an event that takes anIRepo
and addsnull
to its event handler." 并且...不知何故这让事件发生了?+= null
操作没有 return 任何东西,我一直无法弄清楚如何将其理解为该处理程序正在寻找的事件。我发现许多文章和 SO 帖子表明这就是它是如何完成的,但是其中 none(我已经找到)解释了 为什么 。 这应该怎么读?
假设我有一个接口 ITest
只有一个方法:
public interface ITest
{
bool IsEvent(int input);
}
然后我想模拟这个 - 请记住,现在我 没有 实际具体 class.
var mock = new Mock<ITest>();
现在我想设置 2 个电话:
mock.Setup(x => x.IsEven(1)).Returns(false);
mock.Setup(x => x.IsEven(2)).Returns(true);
这是对模拟对象说的:
If your method IsEven gets called with a value of 1 then return false.
If your method IsEven gets called with a value of 2 then return true.
您正在设置模拟对象的行为。
所以如果我在代码中这样做:
var for1 = mock.Object.IsEven(1);
var for2 = mock.Object.IsEven(2);
变量 for1
将为假而 for2
将为真,因为我告诉模拟对象它应该做什么。 Setup
的参数实际上表示 "This is the behaviour I want you to look out for and I will then tell you what to do"。在我的例子中,我使用 Returns
方法来指定在特定情况下从我的模拟对象实际返回的内容。
在您的具体情况下:
mockRepo.Setup(x => x.AddRecord(null))
.Raises(m => m.FailedDatabaseRequest += null, this, EventArgs.Empty);
这是对模拟对象说的
If someone calls the AddRecord method with a parameter of null then raise an event of type FailedDatabaseRequest
有关 Raises
方法的更多信息,请查看此处的 Moq quickstart documentation for events。
有关使用 Moq 引发事件的更深入的视图,有一些有用的信息 here - 特别是它讨论了让您有些困惑的 += null
:
To raise an event from a mock object we use its Raise method. This accepts two parameters. The first is a lambda expression that includes an empty event subscriber for the event to raise. Although not the most elegant syntax, this is required to allow Moq to understand how the event is used. The second parameter provides the event arguments that will be included with the event.
回答自己的问题。
我的困惑源于不理解 C# 表达式的工作原理(不是 lambda 表达式,而是具体 Expression<>
)。它们暴露了编译器理论(特别是 "expression trees"),可用于将 lambda 解构为多个部分,包括参数、常量、二元运算符等。 Moq利用了这一点,并使用这些片段来构造自己的具有指定功能的对象+支持代码以进行验证。我不知道 C# 可以做到这一点。
解惑的系列教程:C# Expression Trees