Mar*_*age 561
序言:如果你在字典中查找名词模拟,你会发现这个单词的一个定义是作为模仿的东西.
模拟主要用于单元测试.被测对象可能依赖于其他(复杂)对象.要隔离要通过模拟真实对象行为的模拟替换其他对象的对象的行为.如果将真实对象合并到单元测试中是不切实际的,这将非常有用.
简而言之,模拟是创建模拟真实对象行为的对象.
有时您可能想要区分嘲弄而不是剔除.关于这个主题可能存在一些分歧,但我对存根的定义是一个"最小"的模拟对象.存根实现了足够的行为以允许被测对象执行测试.
模拟就像一个存根,但测试也将验证被测对象是否按预期调用模拟.部分测试是验证模拟是否正确使用.
举个例子:您可以通过实现用于存储记录的简单内存结构来存根数据库.然后,测试对象可以读取和写入数据库存根的记录,以允许它执行测试.这可以测试与数据库无关的对象的某些行为,并且仅包括数据库存根以使测试运行.
如果您想要验证测试对象是否将某些特定数据写入数据库,则必须模拟数据库.然后,您的测试将包含有关写入数据库mock的内容的断言.
Hon*_*ney 75
其他答案解释了什么是嘲弄.让我通过一个例子引导你.相信我,它实际上比你想象的要简单得多.
tl; dr它是原始类的子类.它还注入了其他数据,因此您可以避免测试注入的部分,并专注于测试其余代码.
假设您正在编写iOS应用程序并进行网络调用.您的工作就是测试您的应用程序.测试/识别网络呼叫是否按预期工作不是您的责任.测试它是另一方(服务器团队)的责任.您必须删除此(网络)依赖项,然后继续测试所有围绕它的代码.
网络呼叫可以使用JSON响应返回不同的状态代码404,500,200,303等.
您的应用程序可能适用于所有这些应用程序(如果出现错误,您的应用程序应该抛出预期的错误).你用mocking做的是你创建'虚构 - 类似于真实的'网络响应(比如带有JSON文件的200代码)并测试你的代码而不用 "进行真正的网络调用并等待你的网络响应".您手动对所有类型的网络响应进行硬编码/返回网络响应,并查看您的应用是否按预期工作.(你从不假设/测试200不正确的数据,因为这不是你的责任,你的责任是用正确的200 测试你的应用程序,或者在400,500的情况下,你测试你的应用程序是否抛出正确的错误)
这创造虚构 - 类似于真实被称为嘲弄.
为此,您无法使用原始代码(您的原始代码没有预先插入的响应,对吧?).您必须向其添加内容,注入/插入通常不需要的虚拟数据(或类的一部分).
因此,您将原始类子类化并添加所需的任何内容(此处为网络HTTPResponse,数据OR,如果失败,您传递正确的errorString,HTTPResponse),然后"测试子类"即模拟类.
您不再测试原始课程.模拟/子类代表原始类进行测试
长话短说,嘲笑是为了简化和限制你正在测试的东西,也让你按照课程所依赖的方式提供.在这个例子中,你避免测试的网络电话本身,而是考验你希望你的应用程序是否适用与注入输出/响应 -通过嘲讽类
不用说,您可以单独测试每个网络响应.
现在,我一直想到的一个问题是:合同/终点以及我的API的JSON响应基本上都会不断更新.如何编写考虑到这一点的单元测试?
详细说明:假设模型需要一个名为的键/字段username
.你测试这个,你的测试通过.2周后,后端将密钥的名称更改为id
.你的测试仍然通过.对?或不?
后端开发人员是否有责任更新模拟.我们的协议是否应该提供更新的模拟?
上述问题的答案是:单元测试+作为客户端开发人员的开发过程应该/将捕获过时的模拟响应.如果你问我怎么样?答案是:
如果没有使用更新的API,我们的实际应用程序将失败(或者没有失败但没有所需的行为)...因此,如果失败...我们将对我们的开发代码进行更改.这再次导致我们的测试失败....我们将不得不纠正它.(实际上,如果我们要正确地执行TDD过程,我们不会写任何关于该字段的代码,除非我们为它编写测试...并看到它失败然后去为它编写实际的开发代码.
这一切都意味着后端不必说:"嘿,我们更新了模拟"......它最终通过代码开发/调试发生.因为它是开发过程的全部内容!虽然如果后端为您提供模拟响应,那么它会更容易.
我的全部观点是,提出一些脚本来获取API的更新模拟效率很低.TDD也没有将100%的努力放在自动完成任务上,而没有任何人为干预.部分过程是手动更新JSON并召开简短会议以确保其值是最新的.
本节的编写归功于我们的CocoaHead聚会小组的讨论
仅适用于iOS开发人员:
一个非常好的嘲弄的例子是Natasha Muraschev的这个实用的协议导向谈话刚刚跳到分钟18:30.
我真的很喜欢成绩单中的这一部分:
因为这是测试...我们确实希望确保调用该
get
函数Gettable
,因为它可以返回,理论上该函数可以从任何地方分配食物项目数组.我们需要确保它被调用;
Dav*_*all 31
SO上有很多答案,网上有关于嘲笑的好帖子.你可能想要开始寻找的一个地方是Martin Fowler Mocks Are Not Stubs的帖子,他讨论了许多嘲笑的想法.
在一个段落中 - Mocking是一种特殊技术,允许测试代码单元而不依赖于依赖性.通常,模拟与其他方法的不同之处在于,用于替换代码依赖关系的模拟对象将允许设置期望 - 模拟对象将知道代码如何调用它以及如何响应.
你的原始问题提到了TypeMock,所以我在下面给出了答案:
它提供了免费模拟框架(如RhinoMocks和Moq)的所有功能,以及一些更强大的选项.
你是否需要TypeMock是值得商榷的 - 你可以用免费的模拟库做大多数你想要的模拟,而且很多人认为TypeMock提供的功能通常会让你远离完美的封装设计.
正如另一个答案所说'TypeMocking'实际上并不是一个定义的概念,但可以理解为TypeMock提供的模拟类型,使用CLR分析器在运行时拦截.Net调用,提供更大的假对象能力(不是要求)例如需要接口或虚拟方法).
Mock是一种方法/对象,以受控方式模拟真实方法/对象的行为.模拟对象用于单元测试.
通常,测试下的方法会调用其中的其他外部服务或方法.这些被称为依赖项.一旦被模拟,依赖关系就像我们定义它们一样.
由于依赖项由模拟控制,我们可以轻松地测试我们编码的方法的行为.这是单元测试.
模拟类型的目的是切断依赖关系,以便将测试隔离到特定单元.存根是简单的代理,而模拟是可以验证使用的代理.模拟框架是一种可以帮助您生成存根和模拟的工具.
编辑:由于原来的措辞提到"类型嘲笑"我得到的印象,这与TypeMock有关.根据我的经验,一般术语只是"嘲弄".请随意忽略以下有关TypeMock的信息.
TypeMock Isolator与大多数其他模拟框架的不同之处在于它可以动态修改IL.这允许它模拟大多数其他框架无法模拟的类型和实例.要使用其他框架模拟这些类型/实例,您必须提供自己的抽象并模拟这些.
TypeMock以干净的运行时环境为代价提供了极大的灵活性.作为TypeMock实现其结果的方式的副作用,使用TypeMock时有时会得到非常奇怪的结果.