内容简介:单元测试期间, 被测单元会存在一些外部依赖的情况。而单测中我们更加注重被测对象自身的功能和行为,以及与外部依赖的交互行为,比如是否调用,调用中参数,调用的次数和顺序以及返回的结果或发生的异常等,并不需要关注外部依赖的具体细节。当然你页可以选择这两部分一起测试,可大声念一遍我们的术语:「单元测试」。这样是否已经和我们测试的原则相违背了,可缺失被测单元再缺失外部依赖的情况下,测试是不能正常进行的,我们陷入了两难境界,是否要继续遵守我们的原则?
单元测试期间, 被测单元会存在一些外部依赖的情况。
而单测中我们更加注重被测对象自身的功能和行为,以及与外部依赖的交互行为,比如是否调用,调用中参数,调用的次数和顺序以及返回的结果或发生的异常等,并不需要关注外部依赖的具体细节。
当然你页可以选择这两部分一起测试,可大声念一遍我们的术语:「单元测试」。这样是否已经和我们测试的原则相违背了,可缺失被测单元再缺失外部依赖的情况下,测试是不能正常进行的,我们陷入了两难境界,是否要继续遵守我们的原则?
为了让我们够能贯彻我们原则,出现了stub 和 mock 此类对象,其功能就是代替外部依赖,从而满足模拟真实场景,帮助我们的单元测试顺利进行。
那如何分辨那些是 stub 和 mock 呢?接下来们来辨析一下这两个概念。
Stub v.s Mock
相同目的
stub 和 mock 对象的出现,其作用都是代替外部依赖,帮助我们顺利进行单元测试。
不同生命周期
Test lifecycle with stubs: Setup - Prepare object that is being tested and its stubs collaborators. Exercise - Test the functionality. Verify state - Use asserts to check object's state. Teardown - Clean up resources.
Test lifecycle with mocks: Setup data - Prepare object that is being tested. Setup expectations - Prepare expectations in mock that is being used by primary object. Exercise - Test the functionality. Verify expectations - Verify that correct methods has been invoked in mock. Verify state - Use asserts to check object's state. Teardown - Clean up resources.
stub 和 mock 在测试的生命周期中表现不同,stub 协助被测单元进行 自身的功能 的校验,mock 更多是测试 被测单元的行为 是否符合预期,且自身在 被测单元行为 触发后进行验证。
看似说的比较玄乎,我们来看看对应不同类型下的代码段:
//产品代码 function A(b) { this.num = 0; this._b = b; } A.prototype.run = function () { this.num = this._b.getNum(); }; //测试代码 describe("测试A类的run方法", function () { it("获得数字", function () { var stub_B = { //B类的桩 getNum: function(){ return 1; } }; var a = new A(stub_B); //注入桩 a.run(); expect(a.num).toEqual(1); }); }); 复制代码
//产品代码 function A(b) { this.num = 0; this._b = b; } A.prototype.run = function () { this.num = this._b.getNum(2); }; //测试代码(Mock为伪代码) describe("测试A类的run方法", function () { it("获得数字", function () { var mockB = Mock.createMock({ getNum: function(){} }); //如果B类存在的话,也可以直接传入B的原型:var mockB = Mock.createMock(B.prototype); Mock.expect(mockB.getNum, 2).return(1).times(1); var a = new A(mockB); a.run(); expect(a.num).toEqual(1); Mock.verify(); //验证期望的行为发生:mockB的getNum传入的参数为2;调用了1次mockB.getNum }); }); 复制代码
看代码 mock 好像比 stub 更加高级,因为 mock 可以再模拟真实环境下,协助被测单元进行测试自身功能,并且对于被测单元的对外部的行为同时进行测试,所以感觉是高级一些。
现状
实际情况下,我们编写的代码段更多是符合 stub 流程中的测试。可表现形式上,mock流程代码不是更高级吗?为什么现实使用中,我们并没有使用 mock 流程中的代码?
因为在通常情况下,我们使用的 mock 是退化的mock,从而是的 mock 流程和 stub 流程在测试使用上行为一致。其实我们是把 mock 当做了 stub 进行使用,其主要区别是 mock 创建时期就没有添加对应的后续期望,导致后期也用不着进行验证。就像这样:
//产品代码 function A(b) { this.num = 0; this._b = b; } A.prototype.run = function () { this.num = this._b.getNum(2); }; //测试代码(Mock为伪代码) describe("测试A类的run方法", function () { it("获得数字", function () { var mockB = Mock.createMock({ getNum: function(){} }); //如果B类存在的话,也可以直接传入B的原型:var mockB = Mock.createMock(B.prototype); Mock.expect(mockB.getNum).return(1); //只指定返回值,没有期望的参数或期望调用的次数。因此不用verify来验证了! var a = new A(mockB); a.run(); expect(a.num).toEqual(1); }); }); 复制代码
为什么我们出现这样情况?很有可能是因为在日常使用中,我们对两者的概念边界都比较模糊,而且开发中经常涉及 mock 数据等术语,更容易干扰我们在单元测试语境下对 mock 的定义。所以在Jest社区中因为区分命名也进行过对应的讨论。 Rename jest.mock to jest.stub
PS: 以上案例代码摘自参考文献。
参考文献
以上所述就是小编给大家介绍的《关于单元测试,我们需要知道什么?- 术语辨析篇》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 大数据分析&人工智能:技术内容价值观的辨析
- JavaScript之call,bind,apply方法及 this 的用法辨析
- 辨析 BI、数据仓库、数据湖和数据中台内涵及差异点
- OpenTracing概念术语介绍
- DevOps最全术语汇总
- Kubernetes概念与术语
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
代码阅读方法与实践
斯平内利斯 / 赵学良 / 清华大学出版社 / 2004-03-01 / 45.00元
代码阅读有自身的一套技能,重要的是能够确定什么时候使用哪项技术。本书中,作者使用600多个现实的例子,向读者展示如何区分好的(和坏的)代码,如何阅读,应该注意什么,以及如何使用这些知识改进自己的代码。养成阅读高品质代码的习惯,可以提高编写代码的能力。 阅读代码是程序员的基本技能,同时也是软件开发、维护、演进、审查和重用过程中不可或缺的组成部分。本书首次将阅读代码作为一项独立课题......一起来看看 《代码阅读方法与实践》 这本书的介绍吧!