虽然很多公司都有自己的测试部门,而且大部分前端开发都不涉及测试,但是鉴于目前前端领域的快速发展,涉及到的越来越多,此外,前端开发人员不能停留在当前状态。我认为学会写好的测试不仅有助于梳理需求和检查代码,也是一个优秀开发人员的体现。首先,不得不推荐两篇文章:前端自动化测试探索测试驱动开发(TDD)入门中的误区Introunittesting到底是什么?需要访问数据库的测试不是单元测试需要访问网络的测试不是需要访问文件系统的单元测试测试不是单元测试---修改代码的艺术我们应该避免什么在单元测试中?ToomuchconditionallogicdoingtoomanythingsintheconstructortoomanyglobalvariablestoomanystaticmethodstoomuchirrelevantlogicexternaldependenciesTDD(Test-drivendevelopment)测试驱动开发(TDD),基本思想是通过驱动整个开发测试。单元测试的首要目的不是能够写出覆盖率大的全部通过的测试代码,而是站在用户(调用者)的角度去尝试功能逻辑的各种可能性,进而辅助提升代码质量测试它是手段而不是目的。测试的主要目的不是为了证明代码是正确的,而是为了帮助发现错误,包括低级错误。测试应该很快。跑得快,写得快测试代码保持干净不忽略失败的测试。一旦团队开始接受1个测试的构建失败,他们就会逐渐习惯2、3、4或更多的失败。在这种情况下,测试集不再有效重要不要误解TDD的核心目的!该测试不是为了覆盖率和正确性,而是作为示例,告诉开发人员要编写什么代码。测试挂起)->Greenlight(编写代码,测试通过)->Refactor(优化代码,确保测试通过)大致流程需求分析,思考实现。考虑如何“使用”产品代码,是实例方法还是类方法,是从构造函数还是方法调用传递参数,方法的名称,返回值等。这个时候,你其实都是在做设计,而设计体现在代码中。这时候测试是红色的,实现代码,让测试是绿色的,重构,然后重复测试,最终满足所有要求:*每个概念都表达清楚*不重复自己*没有多余的东西*通过BDD(Behavior-drivendevelopment)的测试行为驱动开发(BDD),它侧重于通过与利益相关者的讨论获得对预期软件行为的清晰理解,它侧重于从业务角度传达一般过程。定义具体的、可衡量的目标,以找到一种方法,可以实现既定目标的方法和对业务最重要的功能,然后将其描述为像故事一样的具体可执行行为。它的描述方法是基于一些表达准确无误、意义一致的常用词汇。例如,expect、should、assert找到合适的语言和方法来实现行为测试人员检查产品运行结果是否满足预期行为。最大程度交付满足用户预期的产品,避免表达不一致带来的问题*页面自动截图*页面DOM元素检查*运行交互流程工具Mocha+ChaiPhantomJSorCasperJSorNightwatch.jsselenium*withpython*withjsmocha+chai'sAPI/FuncUnitTestmocha是一套前端测试工具,我们可以与其他测试工具一起使用。Chai是一个BDD/TDD测试断言库,提供expectinitial等测试语法以下两篇文章值得一读:TestinginES6withMochaandBabel6UsingBabelsetup$npmimocha--save-dev$npmihai--save-devUsewithes6babel6+$npminstall--save-devbabel-register$npminstallbabel-preset-es2015--save-dev//package.json{"脚本":{"测试":"./node_modules/mocha/bin/mocha--compilersjs:babel-register"},"babel":{"presets":["es2015"]}}babel5+$npminstall--save-devbabel-core//package.json{"scripts":{"test":"./node_modules/mocha/bin/mocha--compilersjs:babel-core/register"}}使用coffeescript$npminstall--savecoffee-script{"scripts":{"test":"./node_modules/mocha/bin/mocha--compilerscoffee:coffee-script/register"}}与es6+coffeescript一起使用完成后...{"scripts":{"test":"./node_modules/mocha/bin/mocha--compilersjs:babel-核心/注册,咖啡:咖啡脚本/注册"}}#$mocha$npmt$npmtestchaiimportchaifrom'chai';constassert=chai.assert;constexpect=chai.expect;constshould=chai.should();foo.should.be.a('string');foo.should.equal('bar');list.should.have.length(3);obj.should.have.property('name');expect(foo).to.be.a('string');expect(foo).to.equal('bar');expect(list).to.have.length(3);expect(obj).to.have.property('flavors');assert.typeOf(foo,'string');assert.equal(foo,'bar');assert.lengthOf(list,3);assert.property(obj,'flavors');Test测试的一个基本思路是从调用者开始函数,在各种情况下调用该函数,检查其容错性以及返回结果是否符合预期importchaifrom'chai';constassert=chai.assert;constexpect=chai.expect;constshould=chai.should();describe('describetest',()=>{it('shouldreturntrue',()=>{letexample=true;//expectexpect(example).not.to.equal(false);expect(example).to.equal(true);//shouldexample.should.equal(true);example.should.be.a(boolen);[1,2].should.have.length(2);});it('shouldcheckanobject',()=>{//对于多层嵌套Object..letnestedObj={a:{b:1}};letnestedObjCopy=Object.assign({},nestedObj);nestedObj.a.b=2;//doafunctiontochangenestedObjCopy.a.bexpect(nestedObjCopy).to.deep.equal(nestedObj);expect(nestedObjCopy).to.have.property('a');});});AsynTestTestingAsynchronousCodewithMochaJSandES7async/awaitmocha不能自动监听异步方法的完成,我们需要在完成后手动调用done()方法,如果我们想回调后要使用异步测试语句,需要使用try/catch进行捕获。done()成功,done(error)失败//普通测试方法it("shouldwork",()=>{console.log("Synchronoustest");});//异步测试方法it("shouldwork",(done)=>{setTimeout(()=>{try{expect(1).not.to.equal(0);done();//成功}catch(err){done(err);//失败}},200);});结束异步测试有两种方式:done或returnPromise。通过返回Promise,您不再需要编写笨重的try/catch语句;},200);});returntestPromise.then(function(result){expect(result).to.equal("Hello!");});});mockmock是一个接口模拟库,我们可以通过它在代码中模拟一些异步操作。React单元测试测试React组件React组件不能通过以上方法直接测试,需要安装enzyme依赖。$npmi--save-devenzyme#$npmi--save-devreact-addons-test-utils假设有这样一个组件://...省略部分导入代码classTestComponenttextendsReact.Component{constructor(props){super(道具);let{num}=props;this.state={clickNum:num}this.handleClick=this.handleClick.bind(this)}handleClick(){let{clickNum}=this.state;this.setState({clickNum:clickNum+1});}render(){let{clickNum}=this.state;return(
