什么是模拟?什么时候应该使用它?
我刚刚阅读了关于模拟对象的维基百科文章,但我仍然不完全清楚它们的目的。 看起来它们是由测试框架创建的对象,而实际对象过于复杂或不可预测(您 100% 确定模拟对象的值是什么,因为您完全控制它们)。
然而,我的印象是所有测试都是用已知值的对象完成的,所以我一定错过了一些东西。 例如,在一个课程项目中,我们的任务是开发一个日历应用程序。 我们的测试套件由我们确切知道它们是什么的事件对象组成,因此我们可以测试多个事件对象、各种子系统和用户界面之间的交互。 我猜这些是模拟对象,但我不知道为什么你不这样做,因为如果没有已知值的对象,你就无法测试系统。
I just read the Wikipedia article on mock objects, but I'm still not entirely clear on their purpose. It appears they are objects that are created by a test framework when the actual object would be too complex or unpredictable (you know 100% sure what the values of the mock object are because you fully control them).
However, I was under the impression that all testing is done with objects of known values, so I must be missing something. For example, in a course project, we were tasked with a calendar application. Our test suite consisted of event objects that we knew exactly what they were so we could test the interactions between multiple event objects, various subsystems, and the user interface. I'm guessing these are mock objects, but I don't know why you wouldn't do this because without the objects of known values, you can't test a system.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
模拟对象不仅仅是具有已知值的对象。 它是一个与无法在测试中使用的复杂对象(如数据库连接和结果集)具有相同接口的对象,但具有您可以在测试中控制的实现。
有一些模拟框架允许您即时创建这些对象,本质上允许您说这样的话:用 foo 方法创建一个对象,该方法接受一个 int 并返回一个 bool。 当我传递 0 时,它应该返回 true。 然后您可以测试使用 foo() 的代码,以确保它做出适当的反应。
Martin Fowler 有一篇关于模拟的精彩文章:
A mock object is not just an object with known values. It is an object that has the same interface as a complex object that you cannot use in test (like a database connection and result sets), but with an implementation that you can control in your test.
There are mocking frameworks that allow you to create these objects on the fly and in essence allow you to say something like: Make me an object with a method foo that takes an int and returns a bool. When I pass 0, it should return true. Then you can test the code that uses foo(), to make sure it reacts appropriately.
Martin Fowler has a great article on mocking:
想想拥有客户端和服务器软件的经典案例。 要测试客户端,需要服务器; 要测试服务器,您需要客户端。 这使得单元测试几乎不可能——不使用模拟。 如果您模拟服务器,则可以单独测试客户端,反之亦然。
模拟的目的不是复制它所模拟的事物的行为。 它更像是一个简单的状态机,其状态变化可以通过测试框架进行分析。 因此,客户端模拟可能会生成测试数据,将其发送到服务器,然后分析响应。 您期望对特定请求得到一定的响应,因此您可以测试是否得到它。
Think of the classic case of having client and server software. To test the client, you need the server; to test the server, you need the client. This makes unit testing pretty much impossible - without using mocks. If you mock the server, you can test the client in isolation and vice versa.
The point of the mock is not to duplicate the behaviour of the things its mocking though. It is more to act as a simple state machine whose state changes can be analysed by the test framework. So a client mock might generate test data, send it to the server and then analyse the response. You expect a certain response to a specific request, and so you can test if you get it.
我同意一切@Lou Franco 说,你绝对应该阅读 @Lou Franco 为你指出的关于测试双打的 Martin Fowler 优秀文章。
任何测试替身(假的、存根或模拟)的主要目的是隔离被测对象,以便单元测试仅测试该对象(而不是其依赖项以及与之协作或交互的其他类型)。
提供对象所依赖的接口的对象可以用来代替实际的依赖关系,以便可以预期某些交互将会发生。 这可能很有用,但围绕基于状态的测试与基于交互的测试存在一些争议。 过度使用模拟期望将导致脆弱的测试。
测试替身的另一个原因是消除对数据库或文件系统或其他类型的依赖,这些类型的设置或执行耗时的操作成本高昂。 这意味着您可以将单元测试您感兴趣的对象所需的时间保持在最低限度。
I agree with everything @Lou Franco says and you should definitely read the excellent Martin Fowler article on test doubles that @Lou Franco points you to.
The main purpose of any test double (fake, stub or mock) is to isolate the object under test so that your unit test is only testing that object (not its dependencies and the other types it collaborates or interacts with).
An object that provides the interface that your object is dependent on can be used in place of the actual dependency so that expectations can be placed that certain interactions will occur. This can be useful but there is some controversy around state-based vs. interaction-based testing. Overuse of mock expectation will lead to brittle tests.
A further reason for test doubles is to remove dependencies on databases or file systems or other types that are expensive to set up or perform time consuming operations. This means you can keep the time required to unit test the object you're interested in to a minimum.
下面是一个示例:如果您正在编写填充数据库的代码,您可能需要检查特定方法是否已将数据添加到数据库中。
设置数据库的副本用于测试存在一个问题,如果您假设调用被测试方法之前没有记录,之后有一条记录,那么您需要将数据库回滚到之前的状态,从而增加了开销用于运行测试。
如果您假设只比以前多了一条记录,则它可能会与连接到同一数据库的第二个测试人员(甚至同一代码中的第二个测试)发生冲突,从而导致依赖性并使测试变得脆弱。
模拟允许您保持测试彼此独立并且易于设置。
这只是一个例子 - 我相信其他人可以提供更多。
我 100% 同意其他贡献者关于此主题的观点,尤其是对 Martin Fowler 文章的建议。
Here's an example: if you're writing code that populates a database you may want to check if a particular method has added data to the database.
Setting up a copy of the database for testing has the problem that if you assume there are no records before the call to the tested method and one record after, then you need to roll back the database to a previous state, thus adding to the overhead for running the test.
If you assume there is only one more record than before, it may clash with a second tester (or even a second test in the same code) connecting to the same database, thus causing dependencies and making the tests fragile.
The mock allows you to keep the tests independent of each other and easy to set up.
This is just one example - I'm sure others can supply more.
I agree 100% with the other contributors on this topic, especially with the recommendation for the Martin Fowler article.
您可能对我们的书感兴趣,请参阅 http://www.grinding-object-orientation- software.com/。 它是用 Java 编写的,但这些想法仍然适用。
You might be interested in our book, see http://www.growing-object-oriented-software.com/. It's in Java, but the ideas still apply.