mock vs stub vs spy
Sinon 是用于 JavaScript 的测试框架,适用于任何单元测试框架。
Sinon 将测试为三种类型:
Spies:提供有关函数调用的信息,而不会影响其行为
Stubs:类似于 Spies,但完全取代了功能。这样就可以使存根函数做任何你喜欢的事情 - 抛出异常,返回一个特定的值等等
Mocks:通过组合 Spies 和 Stubs,可以更轻松地替换整个对象
spy、stub、mock 用法
假设我们有 Todo.ts 代码如下。
// Todo.tsexport default class Todo {private todos: string[] = [];private ajax: any;constructor(ajax?) {ajax && this.ajax = ajax;}add(content) {this.todos.push(content);}printFirstTodo() {console.log(this.todos[0]);}syncClound() {this.ajax && this.ajax.get("/todo.json", data => {this.todos = data;});}}
然后我们使用 Sinon 来为它做单元测试。分别使用 spy、stub、mock 来做单元测试。
spy
// Todo.test.ts
import * as sinon from "sinon";
// 引入 chai 作为断言库
import { expect } from "chai";
import Todo from "./Todo";
describe("测试 Todo", () => {
it("spy print", () => {
const t = new Todo();
// 用 sinon.spy 监控 console.log 函数的执行,并不替换其原有的实现
sinon.spy(console, "log");
t.add("Go to school");
t.add("Sleep");
t.printFirstTodo();
// @ts-ignore console.log.calledOnce 无法识别
// 如果 spy 监控的 console.log 函数刚好被调用一次,则返回 true
expect(console.log.calledOnce).to.be.true;
});
});
stub
// Todo.test.ts
import * as sinon from "sinon";
// 引入 chai 作为断言库
import { expect } from "chai";
import Todo from "./Todo";
describe("测试 Todo", () => {
it("stub syncTodoFromCloud", () => {
const t = new Todo();
// 用 stub 模拟 t.add 函数,stubAdd 函数被模拟为一个空函数
const stubAdd = sinon.stub(t, "add").callsFake(() => {});
// 执行被模拟的 stubAdd 函数,这时候 'Go to school' 并没有被真正地 push
stubAdd("Go to school");
// 尝试打印,会打印出 undefined
t.printFirstTodo();
// 我们期望 stubAdd 被执行了一次
expect(stubAdd.calledOnce).to.be.true;
});
});
mock
// Todo.test.ts
import * as sinon from "sinon";
// 引入 chai 作为断言库
import { expect } from "chai";
import Todo from "./Todo";
describe("测试 Todo", () => {
it("mock syncTodoFromCloud", () => {
const t = new Todo();
// 这时候 console 已经被 mock 完全 mock 了
// 这里可以调用console下的任何方法,但并不会执行
const mock = sinon.mock(console);
// 由于 console 已经完全被 mock了,所以我们这里可以提前描述我们预期的行为
mock.expects("log").calledOnce;
t.add("Go to school");
t.printFirstTodo();
// 校验
mock.verify();
});
});
测试结果![[资料] mock vs stub vs spy - 图3](/uploads/projects/u196011@mr49oq/2de5d7256427b04d853ef6b31fe85373.png)
最后我们用一张图来总结一下三者的区别![[资料] mock vs stub vs spy - 图4](/uploads/projects/u196011@mr49oq/0a79f32e284093d27c77dd33b0bcd017.png)
