我們要寫一個函式,pow(x, n) 該函式將產出 x 的 n 次方,在創建函式之前可以描述該函式的功能有 3 個規範。
describe("title", function() { ... }) 描述函式名稱。
it("title", function() { ... }) 描述函式功能
assert.equal(value1, value2) 帶入參數測試函數的產出是否正確
The development flow
撰寫規範
撰寫基本函式可以跑測試
執行測試框架 mocha ,檢測函示是否正確
增加更多案例到測試中
測試失敗修改函式
重複 3 ~ 5 步驟
The spec in action
測試主要用到 3 個 librarues。
mocha 主要執行的框架 包含 descibeit 等函數。
chai 有很多 assertions 函式,範例使用 assert.equal。
Sinon 用來監視函數模擬內建函式。
<!DOCTYPE html>
<html>
<head>
<!-- add mocha css, to show results -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mocha/3.2.0/mocha.css">
<!-- add mocha framework code -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/3.2.0/mocha.js"></script>
<script>
mocha.setup('bdd'); // minimal setup
</script>
<!-- add chai -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.5.0/chai.js"></script>
<script>
// chai has a lot of stuff, let's make assert global
let assert = chai.assert;
</script>
</head>
<body>
<script>
function pow(x, n) {
/* function code is to be written, empty now */
}
</script>
<!-- the script with tests (describe, it...) -->
<script src="test.js"></script>
<!-- the element with id="mocha" will contain test results -->
<div id="mocha"></div>
<!-- run tests! -->
<script>
mocha.run();
</script>
</body>
</html>
頁面分為 5 個部分
head 引入 libraries
script 撰寫測試的函示
測試程式碼寫在 test.js
<div id='mocha'> 用來輸出 mocha 執行的結果
mocha.run() 執行 mocha
Improving the spec
增加更多情況到測試中,一個測試只檢查一個功能。
// method1
describe("pow", function() {
it("raises to n-th power", function() {
assert.equal(pow(2, 3), 8);
assert.equal(pow(3, 4), 81);
});
});
// method2 better
describe("pow", function() {
it("2 raised to power 3 is 8", function() {
assert.equal(pow(2, 3), 8);
});
it("3 raised to power 3 is 27", function() {
assert.equal(pow(3, 3), 27);
});
});
Improving the implementation
function pow(x, n) {
let result = 1;
for (let i = 0; i < n; i++) {
result *= x;
}
return result;
}
// test
describe("pow", function() {
function makeTest(x) {
let expected = x * x * x;
it(`${x} in the power 3 is ${expected}`, function() {
assert.equal(pow(x, 3), expected);
});
}
for (let x = 1; x <= 5; x++) {
makeTest(x);
}
});
Nested describe
makeTest() 只用在 for 迴圈內,因此將他們綁在一起,下一個測試不會在用到。
describe("pow", function() {
describe("raises x to power 3", function() {
function makeTest(x) {
let expected = x * x * x;
it(`${x} in the power 3 is ${expected}`, function() {
assert.equal(pow(x, 3), expected);
});
}
for (let x = 1; x <= 5; x++) {
makeTest(x);
}
});
// ... more tests to follow here, both describe and it can be added
});
describe("test", function() {
before(() => alert("Testing started – before all tests"));
after(() => alert("Testing finished – after all tests"));
beforeEach(() => alert("Before a test – enter a test"));
afterEach(() => alert("After a test – exit a test"));
it('test 1', () => alert(1));
it('test 2', () => alert(2));
});
// result
Testing started – before all tests (before)
Before a test – enter a test (beforeEach)
1
After a test – exit a test (afterEach)
Before a test – enter a test (beforeEach)
2
After a test – exit a test (afterEach)
Testing finished – after all tests (after)
Extending the spec
增加規範,程式碼出現錯誤,修改程式碼。
// add spec
describe("pow", function() {
// ...
it("for negative n the result is NaN", function() {
assert.isNaN(pow(2, -1));
});
it("for non-integer n the result is NaN", function() {
assert.isNaN(pow(2, 1.5));
});
});
// improve pow(x ,n)
function pow(x, n) {
if (n < 0) return NaN;
if (Math.round(n) != n) return NaN;
let result = 1;
for (let i = 0; i < n; i++) {
result *= x;
}
return result;
}
assert.equal(value1, value2) – checks the equality value1 == value2.
assert.strictEqual(value1, value2) – checks the strict equality value1 === value2.
assert.notEqual, assert.notStrictEqual – inverse checks to the ones above.
assert.isTrue(value) – checks that value === true
assert.isFalse(value) – checks that value === false