Node-JS专精09_02使用chai和sinon

使用chai进行测试

步骤

  • yarn global add typescript ts-node mocha 全局安装
  • 创建目录 promise-demo
  • yarn init -y / npm init -y
  • yarn add chai mocha --dev
  • yarn add @types/chai @types/mocha --dev 添加对应库的类型声明文件
  • 创建 test/index.ts

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import * as chai from "chai";

    const assert = chai.assert;

    describe("Chai 的使用",()=>{
    it("可以测试相等",()=>{
    assert(1 === 1);

    // 因为我们用的是 ts, 你在任何一行在上 // @ts-ignore 那么ts就不会管这行符合不符合逻辑
    // 之前如果不加会报错, 因为 2 永远不等于 3 ,你这样写是没意义的
    // 由于你是在测试,所以经常会写这种代码
    // @ts-ignore
    assert( 2 === 3)
    })
    })
  • 添加运行命令 mocha -r ts-node/register test/**/*.ts 运行测试

简要说明

  • mocha 是用来提供 describe / it这两个函数 以及,yarn test 后命令行里的漂亮输出的
  • chai 是用来提供 assert 的

为了以后方便把 测试命令添加到 package.json里

1
2
3
4
5
6
7
8
9
10
11
"scripts":{
"test":"mocha -r ts-node/register test/**/*.ts"
},

// 然后运行 yarn test 结果报错了
// 因为开始的时候 我们是全局安装的 我们直接输入命令会在全局找
// 而 yarn test 会默认从本地找模块

// 所以要把依赖加入本地

yarn add typescript ts-node --dev

完善基本功能

src/promise.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Promise2{
succeed = null;
fail = null;
resolve(){
setTimeout(() => {
this.succeed();
});
}
reject(){
setTimeout(() => {
this.fail();
});
}
constructor(fn){
if(typeof fn !== 'function'){
throw new Error("我只接受函数")
}

fn(this.resolve.bind(this), this.reject.bind(this));
}
then(succeed,fail){
this.succeed = succeed;
this.fail = fail;
}
}

export default Promise2

test/index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import * as chai from "chai";

const assert = chai.assert;
import Promise from "../src/promise";

describe("Promise",()=>{
it("是一个类",()=>{
assert.isFunction(Promise);
assert.isObject(Promise.prototype);
})
it("new Promise() 如果接受的不是一个函数就报错",()=>{
assert.throw(()=>{
// @ts-ignore
new Promise();
})
assert.throw(()=>{
// @ts-ignore
new Promise(1);
})
assert.throw(()=>{
// @ts-ignore
new Promise(false);
})
})

it("new Promise(fn) 会生成一个对象,对象有 then 方法",()=>{
const promise = new Promise(()=>{})
assert.isFunction(promise.then);
})

it("new Promise(fn) 中的 fn立即执行",()=>{
let called = false;
const promise = new Promise(()=>{
called = true;
})
// @ts-ignore
assert(called === true);
})
it("new Promise(fn) 中的 fn 执行的时候接受 resolve 和 reject 两个函数",()=>{
let called = false;
const promise = new Promise((resolve,reject)=>{
called = true;
assert.isFunction(resolve);
assert.isFunction(reject);
})
// @ts-ignore
assert(called === true);
})

it("promise.then(success) 重的 success 会在 resolve 被调用的时候执行",(done)=>{
let called = false;
const promise = new Promise((resolve,reject)=>{
// 该函数没有执行
assert(called === false);
resolve();
setTimeout(() => {
// 该函数执行了
assert(called === true);
done();
});
})
// @ts-ignore
promise.then(()=>{
called = true;
})
})
})

使用 sinon 测试函数

上面我们经常这样来检查函数是不是被调用

1
2
3
4
5
6
7
8
it("new Promise(fn) 中的 fn立即执行",()=>{
let called = false;
const promise = new Promise(()=>{
called = true;
})
// @ts-ignore
assert(called === true);
})

步骤

  • yarn add sinon sinon-chai --dev
  • yarn add @types/sinon @types/sinon-chai --dev

基本用法

1
2
3
4
5
6
7
8
9
10
11
import * as chai from "chai";
import * as sinon from "sinon";
import * as sinonChai from "sinon-chai";
chai.use(sinonChai);
const assert = chai.assert;

it("new Promise(fn) 中的 fn立即执行",()=>{
let fn = sinon.fake();
new Promise(fn);
assert(fn.called);
})

使用 chai 改写测试用例

test/index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import * as chai from "chai";
import * as sinon from "sinon";
import * as sinonChai from "sinon-chai";
chai.use(sinonChai);
const assert = chai.assert;
import Promise from "../src/promise";
import Sinon = require("sinon");

describe("Promise",()=>{
it("是一个类",()=>{
assert.isFunction(Promise);
assert.isObject(Promise.prototype);
})
it("new Promise() 如果接受的不是一个函数就报错",()=>{
assert.throw(()=>{
// @ts-ignore
new Promise();
})
assert.throw(()=>{
// @ts-ignore
new Promise(1);
})
assert.throw(()=>{
// @ts-ignore
new Promise(false);
})
})

it("new Promise(fn) 会生成一个对象,对象有 then 方法",()=>{
const promise = new Promise(()=>{})
assert.isFunction(promise.then);
})

it("new Promise(fn) 中的 fn立即执行",()=>{
let fn = sinon.fake();
new Promise(fn);
assert(fn.called);
})
it("new Promise(fn) 中的 fn 执行的时候接受 resolve 和 reject 两个函数",(done)=>{
new Promise((resolve,reject)=>{
assert.isFunction(resolve);
assert.isFunction(reject);
done();
})
})

it("promise.then(success) 重的 success 会在 resolve 被调用的时候执行",(done)=>{
const success = sinon.fake();
const promise = new Promise((resolve,reject)=>{
// 该函数没有执行
assert.isFalse(success.called);
resolve();
setTimeout(() => {
// 该函数执行了
assert.isTrue(success.called);
done();
});
})
// @ts-ignore
promise.then(success);
})
})

/*
describe("Chai 的使用",()=>{
it("可以测试相等",()=>{
assert(1 === 1);

// 因为我们用的是 ts, 你在任何一行在上 // @ts-ignore 那么ts就不会管这行符合不符合逻辑
// 之前如果不加会报错, 因为 2 永远不等于 3 ,你这样写是没意义的
// 由于你是在测试,所以经常会写这种代码

// @ts-ignore
assert( 2 === 3)
})
})
*/