risingstack.com/node-hero-node-js-unit-testing-tutorial/在本教程中,您将了解Node.js中的单元测试是什么以及如何正确进行测试您的应用程序。测试Node.js应用程序您可以将测试视为您创建的应用程序的保护措施。它们不仅会在您的本地机器上运行,还会在CI服务上运行,因此失败的构建不会被推送到生产系统。你可能会问:我应该在我的应用程序中测试什么?我应该进行多少次测试?答案因情况而异,但根据经验,您可以遵循测试金字塔制定的指导方针。基本上,测试金字塔描述了您应该编写单元测试、集成测试和端到端测试。集成测试比端到端测试多,单元测试甚至更多。让我们来看看如何为我们的应用程序添加单元测试!请注意,我们不打算在这里讨论集成测试和端到端测试,因为它们远远超出了本教程的范围。*Node.js应用程序单元测试编写单元测试以查看给定模块(单元)是否工作。所有的依赖关系都被剥离了,这意味着我们为模块提供了虚假的依赖关系。应该为指定模块公开的方法提供测试,而不是内部操作。单元测试剖析每个单元测试都具有以下结构:测试设置调用被测方法来断言每个单元测试应该只测试一个关注点。(当然,这并不意味着您可以只添加一个断言)。用于Node.js单元测试的模块对于单元测试,我们打算使用以下模块:测试运行器:mocha,或磁带断言库:chai,或用于测试spy、stub和mock的断言模块(用于断言):sinon(用于测试设置)。Spy、stub和mock——什么时候使用哪一个?在编写单元测试之前,让我们看看什么是spy、stub和mock!Spy可以使用spy获取有关函数调用的信息,例如函数被调用了多少次,或者传递给它们的参数是什么。it('在发布时调用订阅者',function(){varcallback=sinon.spy()PubSub.subscribe('message',callback)PubSub.publishSync('message')assertTrue(callback.called)})//采用的示例来自sinon文档站点:http://sinonjs.org/docs/StubStub(stub)类似于spy,但它替换了target函数。存根可用于控制方法的行为,从而强制执行代码路径(例如抛出异常),或阻止对外部资源(例如HTTPAPI)的调用。it('调用所有订阅者,即使有异常',function(){varmessage='一个示例消息'varerror='一个示例错误消息'varstub=sinon.stub().throws()varspy1=sinon.spy()varspy2=sinon.spy()PubSub.subscribe(message,stub)PubSub.subscribe(message,spy1)PubSub.subscribe(message,spy2)PubSub.publishSync(message,undefined)assert(spy1.called))assert(spy2.called)assert(stub.calledBefore(spy1))})//使用的示例来自sinon文档网站:http://sinonjs.org/docs/Mockmock是带有预编程行为和期望伪方法。it('当异常发生时调用所有订阅者',function(){varmyAPI={method:function(){}}varspy=sinon.spy()varmock=sinon.mock(myAPI)mock.expects("method").once().throws()PubSub.subscribe("message",myAPI.method)PubSub.subscribe("message",spy)PubSub.publishSync("message",undefined)mock.verify()assert(spy.calledOnce)//使用的示例来自sinon文档站点:http://sinonjs.org/docs/})可以看到,对于mocks,你必须预先定义期望值。*假设你想测试以下模块:constfs=require('fs')constrequest=require('request')functionsaveWebpage(url,filePath){returngetWebpage(url,filePath).then(writeFile)}functiongetWebpage(url){returnnewPromise(function(resolve,reject){request.get(url,function(err,response,body){if(err){returnreject(err)}resolve(body)})})}functionwriteFile(fileContent){letfilePath='page'returnnewPromise(function(resolve,reject){fs.writeFile(filePath,fileContent,function(err){if(err){returnreject(err)}resolve(filePath)})})}module.exports={saveWebpage}该模块做一件事:将网页(基于指定的URL)保存为本地计算机上的文件。为了测试这个模块,我们必须拔掉fs模块和request模块。在我们的RisingStack团队中,在实际为这个模块编写单元测试之前,我们通常会添加一个test-setup.spec.js文件来进行基本的测试设置,例如创建一个sinon沙箱。这节省了在每次测试后编写sinon.sandbox.create()和sinon.sandbox.restore()。//test-setup.spec.jsconstsinon=require('sinon')constchai=require('chai')beforeEach(function(){this.sandbox=sinon.sandbox.create()})afterEach(function(){this.sandbox.restore()})另外请注意,我们总是将测试文件放在实现文件旁边,因此得名.spec.js。在我们的package.json文件中,可以找到这些行:{"test-unit":"NODE_ENV=testmocha'/**/*.spec.js'",}通过这些设置,我们可以自己编写测试!constfs=require('fs')constrequest=require('request')constexpect=require('chai')。expectconstwebpage=require('./webpage')describe('网页模块',function(){it('保存内容',function*(){consturl='google.com'constcontent='
