zoukankan      html  css  js  c++  java
  • Mocha JavaScript TDD

    JavaScript TDD with Mocha

    2014-04-30 02:05 by owenyang, 317 阅读, 0 评论, 收藏编辑

    开发现状

    当新的版本快要发布的时候,大家都忙于加班,加紧修复BUG1、BUG2。我想这就是很多公司开发的现状。 为了不至于让上线的版本挂掉挂掉,少不了就是 人肉测试。 在一个项目中,我们会做许许多多各种各样的测试,这些测试都必不可少的。测试是项目成功不可或缺的一部分。但 人肉测试 不在本博的讨论范围。

    测试大体分为以下几类

    • 单元测试
    • 集成测试
    • 功能测试

    测试驱动开发

    TDD(Test-Driven Development) 从根本上改变了传统的开发模式,它要求你在写代码之前就写好测试,而不仅仅是待你写你代码以后的用作验证的目的。 TDD将测试提到了应用设计的阶段,在这期间你应该用你的测试理清你写代码时的思路,我们称作 Tasking.

    以下是TDD开发时的基本要点

    1. Tasking (将项目需要拆分成小的task)
    2. Red (写测试代码,让其失败,变红)
    3. Green (写实现代码,让其通过,变绿)
    4. Refactor (重构,消失代码中的bad smell)
    5. Repeat (重复以上步骤)

    这就是TDD开发过程中的基本过程,我们就在 “红-绿-红-绿” 中完成我们的软件开发。

    JavaScript TDD

    笔者将通过编写一个传统游戏的方式,来完成一个 JavaScript TDD 的实践。

    4 digits 
    是一个猜数字游戏。在国外称为公牛和母牛,在中国人们就叫它猜数字。游戏的目标是在八次内用尽可能短的时间猜出一个随机的四位数:

    • 顺序与大小都相同的用 A 表示
    • 大小相同,但顺序不同用 B 表示

    比如 输入 1234 | 猜数 2156 | 结果 0A2B

    这是曾经在文曲星上有过的游戏,网友做过一个GUI版的,大家可以看下截图:

    当然,本文的重点是 JavaScript TDD, 不是去实现一个太过细节逻辑。我们就把需求稍微改写一下:

    • 四位数先给定
    • 仅做算法处理(比较所猜数字与给定数字)

    开发准备

    • Node
    • Mocha

    如果不知道 Node, 估计你暂时还不用写 JavaScript。所以,本篇文章可能还不太适合你。


    摩卡是一个功能丰富的运行在 Node 和浏览器上的JavaScript测试框架。它允许你使用你任意喜欢的断言库。比如

    • should.js
    • chai
    • expect.js
    • better-assert

    本次工程就选择 should.js吧,写TDD很优美,下面正式开发我们的TDD之旅。

    工程建立

    复制代码
    1 mkdir -p digits/{src,test}
    2 cd digits
    3 touch src/digits.js test/digitsSpec.js
    4 npm init
    5 npm install -g mocha
    6 npm install should --save-dev
    复制代码

    工程就是这样搭建完成了,我们可以来看一下目录结构( 我把node_modules目录隐藏了): 

    就这样,我们就可以直接运行

    mocha

    跑测试了。当然,我们什么代码都没有写,当时没有测试可以跑,所以结果会是一个 0 passing。那我们正式开始吧。

    测试代码编写

    先写出我们的第一个测试用例吧。 如果输入数字,或者所给数字的长度都不等于4,则返回-1。

    复制代码
     1 var should = require('should'),
     2   Digits = require('../src/digits').Digits;
     3 
     4 describe('Digits', function() {
     5   // Digits.compare(inputNum, givenNum);
     6   describe('#compare()', function() {
     7     it('should return -1 when input and given number length isnt 4', function() {
     8       Digits.compare('123', '').should.equal(-1);
     9       Digits.compare('123', null).should.equal(-1);
    10       Digits.compare('123', '1234').should.equal(-1);
    11       Digits.compare(null, '1234').should.equal(-1);
    12     });
    13   });
    14 });
    复制代码

    嗯,代码看起来不错,我们尝试着 mocha 跑一下。啊哦,意料之中,变红了:

    什么原因喃?原来我们根本没有写实现代码,你这不废话么?确实是这样,这就是TDD中的第一步,。接下来,我们就编写一些代码,让它变绿吧。

    实现代码编写

    我们定义一个简单的Digits的function吧,通过 exports.Digits = Digits; 将函数接口暴露出去。就像这样:

    复制代码
     1 function Digits() {}
     2 
     3 Digits.compare = function(inputNum, givenNum) {
     4   var len = 4;
     5 
     6   if (inputNum === null ||
     7     givenNum === null ||
     8     inputNum.length !== len ||
     9     givenNum.length !== len) {
    10     return -1;
    11   }
    12 }
    13 
    14 exports.Digits = Digits;
    复制代码

    看吧,看起来也很不错的样子,那我们继续跑一下测试吧。啊哈,意料之中,变绿了:

    repeat

    由红变绿之后,这个task也就相当于是完成了。我们又可以按照这样的一个步骤,再写新的测试,然后再将它实现出来。到此为止,一个基本的 JavaScript TDD流程也就完了,趁着热乎劲儿。我们把这个compare 函数的其他测试也一并写了吧。代码如下:

    digitsSepc.js

    复制代码
     1 var should = require('should'),
     2   Digits = require('../src/digits').Digits;
     3 
     4 describe('Digits', function() {
     5   // Digits.compare(inputNum, givenNum);
     6   describe('#compare()', function() {
     7     it('should return -1 when input and given number length isnt 4', function() {
     8       Digits.compare('123', '').should.equal(-1);
     9       Digits.compare('123', null).should.equal(-1);
    10       Digits.compare('123', '1234').should.equal(-1);
    11       Digits.compare(null, '1234').should.equal(-1);
    12     });
    13 
    14     it('should return 4A0B when input numbers matched given numbers', function() {
    15       Digits.compare('1234', '1234').should.equal('4A0B');
    16       Digits.compare('5678', '5678').should.equal('4A0B');
    17     });
    18 
    19     it('should return 2A2B when 2 input numbers matched given numbers, and other 2 exist but not the right order', function() {
    20       Digits.compare('2134', '1234').should.equal('2A2B');
    21       Digits.compare('1324', '1234').should.equal('2A2B');
    22       Digits.compare('3214', '1234').should.equal('2A2B');
    23       Digits.compare('4231', '1234').should.equal('2A2B');
    24     });
    25 
    26     it('should return 2A0B when 2 input numbers matched given numbers, and other 2 was wrong numbers', function() {
    27       Digits.compare('1256', '1234').should.equal('2A0B');
    28       Digits.compare('7238', '1234').should.equal('2A0B');
    29       Digits.compare('7834', '1234').should.equal('2A0B');
    30       Digits.compare('1784', '1234').should.equal('2A0B');
    31     });
    32   });
    33 });
    复制代码

    digits.js

    复制代码
     1 function Digits() {}
     2 
     3 Digits.compare = function(inputNum, givenNum) {
     4   var len = 4,
     5     aCount = 0,
     6     bCount = 0;
     7 
     8   if (inputNum === null ||
     9     givenNum === null ||
    10     inputNum.length !== len ||
    11     givenNum.length !== len) {
    12     return -1;
    13   }
    14 
    15   if (inputNum === givenNum) {
    16     return '4A0B';
    17   }
    18 
    19   for (var i = 0; i < len; i++) {
    20     if (inputNum[i] === givenNum[i]) {
    21       aCount++;
    22     } else if (givenNum.indexOf(inputNum[i]) !== -1) {
    23       bCount++;
    24     }
    25   }
    26 
    27   return aCount + 'A' + bCount + 'B';
    28 }
    29 
    30 exports.Digits = Digits;
    复制代码

    最后再来跑一遍 mocha -R spec,结果如下(大功告成啦):

    结语

    大功告成了,此时的你其实可以洗洗睡了,不用再担心你的程序有问题啦。你的测试告诉你,你的程序都是绿色可行的。当然,如果你测试写有的问题就别当别说咯。 测试代码会有一些什么好处呢?

    • 测试代码在那里,可以保证你以后修改代码时,或者重构时不会对已有的功能产生影响。

    这条是很重要的,也是相当重要的。如果没有测试代码的保证,你无从知道你自己所改的代码,对已有的代码会产生什么样的影响。与其每次上线时都得加班改BUG,为啥不先写好测试,上线时早些洗洗睡了呢?

    • 文章声明
    • 作者:Owen
    • 出处: http://www.cnblogs.com/owenyang
    • 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。该博客同步发在 CSDN-博客
     
    分类: Web Front-end
    标签: JavaScriptTDDMochashould
  • 相关阅读:
    IOS Charles(代理服务器软件,可以用来拦截网络请求)
    Javascript中addEventListener和attachEvent的区别
    MVC中实现Area几种方法
    Entity Framework Code First 中使用 Fluent API 笔记。
    自定义JsonResult解决 序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    An entity object cannot be referenced by multiple instances of IEntityChangeTracker 的解决方案
    Code First :使用Entity. Framework编程(8) ----转发 收藏
    Code First :使用Entity. Framework编程(6) ----转发 收藏
    Code First :使用Entity. Framework编程(5) ----转发 收藏
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3701115.html
Copyright © 2011-2022 走看看