Jest学习文档(一)

141 阅读3分钟

Jest是什么?

Jest 是一款优雅、简洁的 JavaScript 测试框架

为什么要使用测试框架?

测试框架可以帮助我们更简单的写出测试代码, 而测试代码可以保证我们代码的正常运行

学习经验

官方文档

jestjs.io/zh-Hans

全局类型

我注意到, 在成功安装jest后, 测试文件里的test和expect等函数都有了类型提示, 查看引入发现在jest包下的index.d.ts已经进行了全局的类型声明

1676517467573.jpg 顺便让我学习了一下ts的全局类型声明和模块类型声明

全局实现

由类型声明又引发出一个问题, test函数的实现又是从哪来的呢? 在测试文件中并没有引入jest模块, 所以试着去直接用ts-node运行测试文件, 发现并没有找到test函数, 由此得出结论, 当我们npx jest时, jest的可执行文件帮我们注入了全局环境

匹配器

以下代码来自官方文档

test('two plus two is four', () => {
  expect(2 + 2).toBe(4);
});

最简单的匹配器是toBe, 它使用Object.is()进行匹配, 对于Object.is()它的特性是
1.区分+0和-0
2.不做隐式转换
3.NaN == NaN 让我们来测试一下

Object.is(+0, -0)
false
+0 === -0
true
Object.is(1,"1")
false
"1"==1
true
Object.is(NaN,NaN)
true
NaN === NaN
false

事实上, 以上内容我每次看到Object.is都会记一次, 但根本记不住
如果你想匹配引用对象的值而不是引用地址, 你可以使用toEqual匹配器, 它会比较对象的值. 有意思的是, 因为我并不知道什么简便的方法比较对象的值, 所以打算看一下jest源码里的实现, 但是我发现我根本看不懂它的源码, 下载下来之后全是报红, 也找不到具体的实现在哪(还是菜啊). 简单提一嘴, 百度一下后, 找到的方法为使用Object.getOwnPropertyNames()配合递归可以事件对象值的比较

那么, 让我们来简单的实现一下expect方法和toBe, toEqual两个匹配器

首先, 分析需求

  1. expect接受一个表达式作为参数
  2. expect的返回值是一个对象, 对象上有toBe和toEqual两个方法
class Mathers {
    constructor(protected readonly expressionVal: unknown) {}
    toBe() {}
    toEqual() {}
}
const expect = (expressionVal: unknown) => {
    return new Mathers(expressionVal);
};
  1. 对于toBe方法, 使用Object.is()来判断相等, 如果相等则控制台不打印信息, 不相等则控制台打印预期值和收到值
  2. 对于toEqual方法, 使用如果是值是对象类型, 则用递归+Object.getOwnPropertyNames来判断值相等, 如果是普通类型, 则使用Object.is()来判断
function toBe() {}

class Mathers {
    constructor(protected readonly expressionVal: unknown) {}
    expectErr(val: unknown) {
        throw new Error(`expect:${this.expressionVal}\nrecieve:${val}`);
    }
    toBe(val: unknown) {
        Object.is(this.expressionVal, val) ? void 0 : this.expectErr(val);
    }
    toEqual(val: unknown) {
        if (
            typeof val === "object" &&
            val !== null &&
            this.expressionVal !== null &&
            typeof this.expressionVal === "object"
        ) {
            const compareObj = (val1: unknown, val2: unknown) => {
                if (
                    typeof val1 !== "object" ||
                    val2 !== "object" ||
                    val1 === null ||
                    val2 === null
                ) {
                    Object.is(val1, val2) ? void 0 : this.expectErr(val);
                } else {
                    Object.getOwnPropertyNames(val1).forEach((item) => {
                        compareObj(val1[item], val2[item]);
                    });
                }
            };
        } else {
            this.toBe(val);
        }
    }
}
const expect = (expressionVal: unknown) => {
    return new Mathers(expressionVal);
};

接着, 来试验一下

var a = 1;
var obj1 = {
    a: a,
};
var obj2 = {
    a: a,
};
expect(a).toBe(1); //正常
expect(a).toEqual(1); //正常
expect(obj1).toBe(obj2); //报错
expect(obj1).toEqual(obj2); //正常

ok, 符合要求

其它匹配器

jest的官方文档中还列出了许多的匹配器, 但事实上, 都可以看成是toBe和toEqual的语法糖, 在日常的测试案例编写中, 只使用toBe和toEqual也是完全够用的.

告一段落