## 问题
你使用CoffeeeScript写了一个简单的计算器,然后你想确认一下它的函数是否如你所想。你决定使用[Jasmine](http://pivotal.github.com/jasmine/)测试框架。
## 详解
使用Jasmine测试框架,把测试写在一个特殊的文件(spec)中,测试中描述了被测代码所期望的功能点。
例如,我们希望我们的计算机可以做加减法,并且能够正确地处理正负数。我们的测试用例如下。
~~~
# calculatorSpec.coffee
describe 'Calculator', ->
it 'can add two positive numbers', ->
calculator = new Calculator()
result = calculator.add 2, 3
expect(result).toBe 5
it 'can handle negative number addition', ->
calculator = new Calculator()
result = calculator.add -10, 5
expect(result).toBe -5
it 'can subtract two positive numbers', ->
calculator = new Calculator()
result = calculator.subtract 10, 6
expect(result).toBe 4
it 'can handle negative number subtraction', ->
calculator = new Calculator()
result = calculator.subtract 4, -6
expect(result).toBe 10
~~~
### 配置Jasmine
想要运行你的测试用例,你必须下载Jasmine,并对其进行配置,具体步骤如下:
1. 下载最新的[Jasmine](http://pivotal.github.com/jasmine/download.html) zip文件;
2. 在你的项目中创建两个文件夹,spec和spec/jasmine;
3. 把下载好的Jasmine文件解压到spec/jasmine文件夹中;
4. 创建一个测试的runner。
### 创建Test Runner
Jasmine能够通过一个spec runner HTML文件在浏览器中运行你的测试用例。spec runner是一个简单的HTML页面,引用了一些必要的JavaScript和CSS文件,包括Jasmine和你的代码。示例如下。
~~~
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2 "http://www.w3.org/TR/html4/loose.dtd">
3 <html>
4 <head>
5 <title>Jasmine Spec Runner</title>
6 <link rel="shortcut icon" type="image/png" href="spec/jasmine/jasmine_favicon.png">
7 <link rel="stylesheet" type="text/css" href="spec/jasmine/jasmine.css">
8 <script src="http://code.jquery.com/jquery.min.js"></script>
9 <script src="spec/jasmine/jasmine.js"></script>
10 <script src="spec/jasmine/jasmine-html.js"></script>
11 <script src="spec/jasmine/jasmine-jquery-1.3.1.js"></script>
12
13 <!-- include source files here... -->
14 <script src="js/calculator.js"></script>
15
16 <!-- include spec files here... -->
17 <script src="spec/calculatorSpec.js"></script>
18
19 </head>
20
21 <body>
22 <script type="text/javascript">
23 (function() {
24 var jasmineEnv = jasmine.getEnv();
25 jasmineEnv.updateInterval = 1000;
26
27 var trivialReporter = new jasmine.TrivialReporter();
28
29 jasmineEnv.addReporter(trivialReporter);
30
31 jasmineEnv.specFilter = function(spec) {
32 return trivialReporter.specFilter(spec);
33 };
34
35 var currentWindowOnload = window.onload;
36
37 window.onload = function() {
38 if (currentWindowOnload) {
39 currentWindowOnload();
40 }
41 execJasmine();
42 };
43
44 function execJasmine() {
45 jasmineEnv.execute();
46 }
47
48 })();
49 </script>
50 </body>
51 </html>
~~~
可以从[gist](https://gist.github.com/2623232)上下载这个spec runner。
SpecRunner.html使用起来也很简单,引入jasmine.js和相关的依赖,然后接着引入编译好的JavaScript文件和测试用例即可。
在上例中,我们引入了有待开发的calculator.js文件(14行)以及编译好的calculatorSpec.js文件(17行)。
## 运行测试用例
只需在浏览器中打开SpecRunner.js就能运行我们的测试用例。在我们的例子中,我们会看到4个失败的spec,总共包含8个没有通过的测试用例(如下)。
![All failing tests](http://island205.com/coffeescript-cookbook.github.com/chapters/testing/images/jasmine_failing_all.jpg)
看起来我们的测试用例没有通过是因为Jasmine无法找到Calculator变量。因为它就没被创建出来过。我们现在来创建,我们创建一个名为js/calculator.coffee的文件。
~~~
# calculator.coffee
window.Calculator = class Calculator
~~~
编译calculator.coffee,然后刷新浏览器,重新运行测试用例。
![Still failing, but better](http://island205.com/coffeescript-cookbook.github.com/chapters/testing/images/jasmine_failing_better.jpg)
现在,未通过的测试用例从原来的8个变成了现在的4个。只增加了一行代码,就有50%的提升。
## 让测试都通过
让我们把方法都实现出来,看看这些测试用例能够通过么?
~~~
# calculator.coffee
window.Calculator = class Calculator
add: (a, b) ->
a + b
subtract: (a, b) ->
a - b
~~~
刷新后,我们看到所有的测试用例都通过了。
![All passing](http://island205.com/coffeescript-cookbook.github.com/chapters/testing/images/jasmine_passing.jpg)
## 重构测试用例
现在我们的测试通过了,我们应该检查一下我们的代码或者测试用例是否可以重构一下。
在我们的spec文件中,每个测试用例都会创建它自己的calculator实例。这会让我们的测试用例过于重复,对于较大的测试用例尤其如此。理想情况下,我们应当考虑把那些初始化的代码移进每个测试运行之前都需例行运行的代码中。
恰好Jasmine有一个名为beforeEach的函数可以实现这种需求。
~~~
describe 'Calculator', ->
calculator = null
beforeEach ->
calculator = new Calculator()
it 'can add two positive numbers', ->
result = calculator.add 2, 3
expect(result).toBe 5
it 'can handle negative number addition', ->
result = calculator.add -10, 5
expect(result).toBe -5
it 'can subtract two positive numbers', ->
result = calculator.subtract 10, 6
expect(result).toBe 4
it 'can handle negative number subtraction', ->
result = calculator.subtract 4, -6
expect(result).toBe 10
~~~
当我们重新编译我们的spec刷新浏览器之后,测试还是都通过了。
![All passing](http://island205.com/coffeescript-cookbook.github.com/chapters/testing/images/jasmine_passing.jpg)
- 贡献
- 作者
- 授权协议
- 1、Syntax
- 在服务端和客户端重用代码
- For循环
- 嵌入JavaScript代码
- 值域
- 2、Classes and Objects
- 类方法和实例方法
- CoffeeScript式的Type函数
- 链式调用
- 克隆对象(深度克隆)
- 不存在就赋值为对象字面量
- 类变量
- 3、Strings
- 分割字符串
- 字符串匹配
- 查找子字符串
- 让整个字符串小写
- 大写整个字符
- 去掉字符串首尾的空白
- 生成唯一的ID
- 首字母大写
- 重复字符串
- 字符串插值
- 4、Arrays
- Python式的Zip函数 Python-like Zip Function
- 数组去重 Removing Duplicate Elements from Arrays
- 基于数组构建字典对象 Creating a dictionary Object from an Array
- 数组转成字符串 Creating a String from an Array
- 检查每一个元素 Testing Every Element
- 数组最大值
- 过滤数组 Filtering Arrays
- 定义区间数组 Define Ranges Array
- 转置数组 Reversing Arrays
- 化简数组 Reducing Arrays
- 使用数组来做值交换 Using Arrays to Swap Variables
- 列表解析 List Comprehensions
- 检查值的类型是否是数组
- 连接数组
- 搅乱数组中的元素 Shuffling Array Elements
- 数组映射 Mapping Arrays
- 5、Dates and Times
- Calculate Phase of the Moon for a Date
- 找出某月的最后一天是几号 Finding the Last Day of the Month
- 获取两个日期相差的天数 Get Days Between Two Dates
- 计算复活节岛日期 Calculate the Date of Easter Sunday
- 计算感恩节的日期(美国和加拿大) Calculate the Date of Thanksgiving (USA and Canada)
- 计算上一个(下一个)月份 Finding Last (or Next) Month
- 6、Math
- 快速逆平方根
- 一个随机整数的函数
- 更快的斐波那契算法
- 生成可预测的随机数
- 弧度与度转换
- 生成随机数
- 数学常数
- 7、Functions
- 反抖动函数 Debounce Functions
- 参数数组化 Splat Arguments
- 当函数调用的括号不可以省略时 When Function Parentheses Are Not Optional
- 递归函数 Recursive Functions
- 8、Metaprogramming
- 扩展内置对象 Extending Built-in Objects
- 检测并创建缺失的函数 Detecting and Creating Missing Functions
- 9、jQuery
- 回调绑定
- 创建jQuery插件
- AJAX
- 10、Ajax
- 不依赖jQuery的Ajax请求 Ajax Request Without jQuery
- 11、Regular Expressions
- 替换子字符串 Replacing Substrings
- 使用定点 Using Heregexes
- 使用HTML字符实体替换HTML标签 Replacing HTML Tags with HTML Named Entities
- 搜索子字符串 Searching for Substrings
- 12、Networking
- 简单的服务器
- 双向客户端
- 最简单的HTTP客户端
- 最简单的HTTP服务器
- 简单的客户端
- 双向服务端 Bi-Directional Server
- 13、Design Patterns
- 命令模式
- 单例模式
- 策略模式 Strategy Pattern
- 建造者模式 Builder Pattern
- 备忘录模式 Memento Pattern
- 解释器模式 Interpreter Pattern
- 装饰者模式
- 桥接模式
- 工厂方法模式
- 14、Databases
- MongoDB
- SQLite
- 15、Testing
- 使用Jasmine测试