## 問題
你使用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個沒有通過的測試用例(如下)。

看起來我們的測試用例沒有通過是因為Jasmine無法找到Calculator變量。因為它就沒被創建出來過。我們現在來創建,我們創建一個名為js/calculator.coffee的文件。
~~~
# calculator.coffee
window.Calculator = class Calculator
~~~
編譯calculator.coffee,然后刷新瀏覽器,重新運行測試用例。

現在,未通過的測試用例從原來的8個變成了現在的4個。只增加了一行代碼,就有50%的提升。
## 讓測試都通過
讓我們把方法都實現出來,看看這些測試用例能夠通過么?
~~~
# calculator.coffee
window.Calculator = class Calculator
add: (a, b) ->
a + b
subtract: (a, b) ->
a - b
~~~
刷新后,我們看到所有的測試用例都通過了。

## 重構測試用例
現在我們的測試通過了,我們應該檢查一下我們的代碼或者測試用例是否可以重構一下。
在我們的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刷新瀏覽器之后,測試還是都通過了。

- 貢獻
- 作者
- 授權協議
- 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測試