什么是严格模拟和非严格模拟?
我已经开始使用最小起订量进行模拟。有人可以向我解释严格和非严格模拟的概念吗?它们如何用于最小起订量?
编辑: 在什么场景下我们使用哪种类型的mock?
I have started using moq for mocking. Can someone explain me the concept of strict and non-strict mocks? How can they can be used in moq?
edit:
in which scenario do we use which type of mock?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不确定最小起订量具体是多少,但以下是严格模拟在 Rhino 中的工作原理。我声明我期望在我的对象
foo
上调用foo.Bar
:如果调用代码确实如此
,那么我就很好,因为完全满足了期望。
但是,如果调用代码是:
那么我的期望失败了,因为我没有明确期望调用
foo.Quux
。总而言之,如果有任何与预期不同的情况,严格的模拟将立即失败。另一方面,非严格模拟(或存根)会很乐意“忽略”对 foo.Quux 的调用,并且它应该返回一个
default(T)
foo.Quux
的返回类型T
。Rhino 的创建者 建议您避免使用严格模拟(并且更喜欢存根),因为您通常不希望测试在收到上述意外调用时失败。当您必须修复数十个依赖于精确原始行为的测试时,它会使重构代码变得更加困难。
I'm not sure about moq specifically, but here's how strict mocks work in Rhino. I declare that I expect a call to
foo.Bar
on my objectfoo
:If the calling code does
then I'm fine because the expectations are exactly met.
However, if the calling code is:
then my expectation failed because I did not explicitly expect a call to
foo.Quux
.To summarize, a strict mock will fail immediately if anything differs from the expectations. On the other hand, a non-strict mock (or a stub) will gladly "ignore" the call to
foo.Quux
and it should return adefault(T)
for the return typeT
offoo.Quux
.The creator of Rhino recommends that you avoid strict mocks (and prefer stubs) because you generally don't want your test to fail when receiving an unexpected call as above. It makes refactoring your code much more difficult when you have to fix dozens of test that relied on the exact original behavior.
曾经遇到过Given/When/Then吗?
此模式出现在 BDD 的场景中,并且也与单元测试相关。
如果您要设置上下文,您将使用该上下文提供的信息。例如,如果您通过 ID 查找某些内容,那就是上下文。如果它不存在,则测试将不会运行。在这种情况下,您想要使用 NiceMock 或 Stub 或其他任何东西 - Moq 的默认运行方式。
如果您想验证结果,可以使用 Moq 的验证。在这种情况下,您想要记录相关的交互。幸运的是,这也是 Moq 默认的运行方式。如果发生您对该测试不感兴趣的事情,它不会抱怨。
当您不希望发生意外的交互时,StrictMock 就可以使用。这就是旧式模拟框架的运行方式。如果您正在做 BDD 风格的示例,您可能不需要这个。与将您感兴趣的行为的各个方面分开相比,它倾向于使测试变得有点脆弱且难以阅读。您必须对上下文和结果以及将发生的所有结果建立期望,无论他们是否感兴趣。
例如,如果您正在测试控制器并模拟验证器和存储库,并且您想验证是否已保存对象,则通过严格模拟,您还必须首先验证是否已验证对象。我更喜欢在单独的示例中查看行为的这两个方面,因为它使我更容易理解控制器的值和行为。
在过去的四年中,我还没有找到一个需要使用严格模拟的示例 - 这要么是我想要验证的结果(即使我验证了它被调用的次数),要么是我可以验证的上下文告诉我是否对所提供的信息做出了正确的反应。因此,回答你的问题:
注意:我强烈偏向 BDD,所以硬核 TDD 可能不同意我的观点,并且这将适合他们的工作方式。
Ever come across Given / When / Then?
This pattern appears in BDD's scenarios, and is also relevant for unit tests.
If you're setting up context, you're going to use the information which that context provides. For instance, if you're looking up something by Id, that's context. If it doesn't exist, the test won't run. In this case, you want to use a NiceMock or a Stub or whatever - Moq's default way of running.
If you want to verify an outcome, you can use Moq's verify. In this case, you want to record the relevant interactions. Fortunately, this is also Moq's default way of running. It won't complain if something happens that you weren't interested in for that test.
StrictMock is there for when you want no unexpected interactions to occur. It's how old-style mocking frameworks used to run. If you're doing BDD-style examples, you probably won't want this. It has a tendency to make tests a bit brittle and harder to read than if you separate the aspects of behaviour you're interested in. You have to set up expectations for both the context and the outcome, for all outcomes which will occur, regardless of whether they're of interest or not.
For instance, if you're testing a controller and mocking out both your validator and your repository, and you want to verify that you've saved your object, with a strict mock you also have to verify that you've validated the object first. I prefer to see those two aspects of behaviour in separate examples, because it makes it easier for me to understand the value and behaviour of the controller.
In the last four years I haven't found a single example which required the use of a strict mock - either it was an outcome I wanted to verify (even if I verify the number of times it's called) or a context for which I can tell if I respond correctly to the information provided. So in answer to your question:
NB: I am strongly biased towards BDD, so hard-core TDDers may disagree with me, and it will be right for the way that they are working.
这是一篇很好的文章。
我通常最终会得到这样的结果
……我对 3 个协作者使用严格的模拟来测试登录(用户名)。我不明白如何永远不应该使用严格模拟。
Here's a good article.
I usually end up having something like this
...and I use Strict mocks for the 3 collaborators to test login(username). I don't see how Strict Mocks should never be used.
我有一个简单的约定:
当被测系统 (SUT) 将调用委托给底层模拟层时,使用严格模拟,而无需真正修改或将任何业务逻辑应用于传递给自身的参数。
当 SUT 将业务逻辑应用于传递给自身的参数并将一些派生/修改的值传递给模拟层时,请使用松散模拟。
例如:
假设我们有数据库提供程序 StudentDAL,它有两种方法:
数据访问接口如下所示:
使用此 DAL 的实现如下所示:
I have a simple convention:
Use strict mocks when the system under test (SUT) is delegating the call to the underlying mocked layer without really modifying or applying any business logic to the arguments passed to itself.
Use loose mocks when the SUT applies business logic to the arguments passed to itself and passes on some derived/modified values to the mocked layer.
For eg:
Lets say we have database provider StudentDAL which has two methods:
Data access interface looks something like below:
The implementation which consumes this DAL looks like below: