如何模拟也属于目标类本身的方法?
假设我们正在测试一个类 C,它有 2 个方法 M1 和 M2,其中 M1 在执行时调用 M2。
测试M2是可以的,但是我们如何测试M1呢?困难在于,如果我没有误解的话,我们需要模拟 M2。
如果是这样,我们如何在测试同一个类中定义的方法时模拟另一个方法?
[编辑]
C 类没有基类。
Let's say we are testing a class C which has 2 methods M1 and M2 where M1 calls M2 when executed.
Testing M2 is ok, but how can we test M1? The difficulty is that we need to mock M2 if I'm not misunderstanding things.
If so, how can we mock another method while testing a method defined in the same class?
[Edit]
Class C has no base classes.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以通过将模拟上的 CallBase 属性设置为
真实。
例如,如果我有这个类:
我可以设置 MethodA 并调用 MethodB:
You can do this by setting the CallBase property on the mock to
true
.For example, if I have this class:
I can setup MethodA and call MethodB:
您应该让对
M1
的调用传递到M2
方法的真实实例。一般来说,您应该测试类的黑盒行为。您的测试不应该关心
M1
碰巧调用M2
- 这是一个实现细节。这与模拟外部依赖项(你应该这样做)不同...
例如,假设我有一个这样的类:
我希望我的测试表明:
调用< code>Merge(first, secondary,strategy) 结果会保存两个已使用提供的规则合并的帐户。
调用
Merge(first, secondary)
会保存两个已使用默认规则合并的帐户。请注意,这两个要求都是用输入和效果来表述的 - 特别是,我不关心类如何实现这些结果,只要确实如此。。
事实上,第二种方法恰好使用第一种方法并不是我关心的事情,甚至我不想强制执行 - 如果我这样做,我将编写非常脆弱的测试。 (甚至有人认为,如果您使用模拟框架弄乱了被测对象,那么您甚至不再测试原始对象,那么您在测试什么?)这是一个内部依赖关系,可以在不违反要求的情况下非常愉快地进行更改:
只要我的测试仅检查输入和效果,我就可以轻松地进行这种重构 - 我的测试甚至会帮助我这样做,因为他们确保我在进行更改时没有破坏课堂。
另一方面,我使用
IAccountDao
来保存合并后的帐户(尽管AccountMerger
不应该关心DAO 的实现,只是它有一个Save()
方法。)此 DAO 是模拟的主要候选者 -AccountMerger 的外部依赖项code> 类,感觉效果 我想检查某些输入。
You should let the call to
M1
pass through to a real instance of theM2
method.In general, you should be testing the black box behaviour of your classes. Your tests shouldn't care that
M1
happens to callM2
- this is an implementation detail.This isn't the same as mocking external dependencies (which you should do)...
For example, say I have a class like this:
I want my tests to show that:
Calling
Merge(first, second, strategy)
results in two accounts getting saved that have been merged using the supplied rule.Calling
Merge(first, second)
results in two accounts getting saved that have been merged using the default rule.Note that both of these requirements are phrased in terms of inputs and effects - in particular, I don't care how the class achieves these results, as long as it does.
The fact that the second method happens to use the first isn't something I care about, or even that I want to enforce - if I do so, I'll write very brittle tests. (There's even an argument that if you've messed about with the object under test using a mocking framework, you're not even testing the original object any more, so what are you testing?) This is an internal dependency that could quite happily change without breaking the requirements:
As long as my tests only check inputs and effects, I can easily make this kind of refactoring - my tests will even help me to do so, as they make sure I haven't broken the class while making changes.
On the other hand, I do about the
AccountMerger
using theIAccountDao
to save accounts following a merge (although theAccountMerger
shouldn't care about the implementation of the DAO, only that it has aSave()
method.) This DAO is a prime candidate for mocking - an external dependency of theAccountMerger
class, feeling an effect I want to check for certain inputs.您不应该模拟目标类中的方法,而应该只模拟外部依赖项。
如果在测试 M1 时模拟 M2 似乎有意义,那么通常意味着您的类做了太多事情。考虑拆分类并将 M2 保留在一个类中,并将 M1 移动到更高级别的类,这将使用包含 M2 的类。那么模拟 M2 就很容易了,而且你的代码实际上会变得更好。
You shouldn't mock methods in the target class, you should only mock external dependencies.
If it seems to make sense to mock M2 while testing M1 it often means that your class is doing too many things. Consider splitting the class and keeping M2 in one class and move M1 to a higher level class, which would use the class containing M2. Then mocking M2 is easy, and your code will actually become better.