Jest Parameterised Testing
重复测试解决方案——参数化测试。
目录
- 前言
- 重复测试
- 参数化测试——数组语法
- 参数化测试——模板字符串语法
- 参数化测试——支持的 API
jest-each
- 概要
前言
jest-each文章标题来源 jest-each
自动化测试对我们项目健壮性是不言而喻的,因为测试是需要对代码覆盖场景各方面的测试,这会导致我们写出很多——只是简单输入输出,不同的测试实例,有没有一种方法能让测试代码显得更加精简凝练呢。
当然是有的,这就是我们要介绍的参数化测试。
重复测试
我们有一个简单的例子,加法计算器:
const add = (x, y) => x + y;
为了,验证程序的正确性,我们需要一个测试:
describe("addition calculator", () => {
it("0 plus 0 equals 0", () => {
expect(add(0, 0)).toBe(0);
});
it("-1 plus -2 equals -3", () => {
expect(add(-1, -2)).toBe(-3);
});
it("1 plus 2 equals 3", () => {
expect(add(1, 2)).toBe(3);
});
it("8 plus 2 equals 10", () => {
expect(add(8, 2)).toBe(10);
});
});
测试运行结果全部通过:
我们观察上面的代码,你就会发现虽然输入输出有所不同,但是逻辑类似,由此造成了测试代码重复,如果需要新增一个测试用例,需要重新复制一份代码。
参数化测试——数组语法
Jest 提供给我们处理这种情况一种方法,就是 Parameterized Tests。
describe("addition calculator", () => {
it.each([
[0, 0, 0],
[-1, -2, -3],
[1, 2, 3],
[8, 2, 10],
])(
`%i plus %i equals %i`,
(x, y, result) => {
expect(add(x, y)).toBe(result);
}
);
});
上面的代码,你可能不明所以,但是心里肯定认同这种写法,因为如果你想更改删除测试输入输出,只需要维护一个二维数组就行了,更加直观。
顺带一提,我当时看 Jest 文档,愣是没明白 each 的用法,什么 The table contains rows
把我整的很懵圈。
我来简单讲下它大致执行逻辑,。
首先,看到 each 你肯定想到了循环,没错 Jest 首先会循环这个二维数组,拿到里面的数组之后,在进行断言,整个过程就类似下面这样:
// each 大致逻辑
const testArr = [
[0, 0, 0],
[-1, -2, -3],
[1, 2, 3],
[8, 2, 10],
];
testArr.forEach(([x, y, result]) => {
test(`${x} plus ${y} equals ${result}`, () => {
expect(add(x, y)).toBe(result);
})
})
// 第一次循环
(0, 0, 0) => {
expect(add(0, 0)).toBe(0);
}
// 第二次循环
(-1, -2, -3) => {
expect(add(-1, -2)).toBe(-3);
}
// 第三次循环
(1, 2, 3) => {
expect(add(1, 2)).toBe(3);
}
// 第四次循环
(2, 8, 10) => {
expect(add(2, 8)).toBe(10);
}
除了,明白 each 的运行逻辑,我们应该还注意到,我们在 test 的 title 这里使用了 %i
这个占位符。如果你足够熟悉 NodeJs ,会发现这其实是一个 printf
formatting,Jest 关于 test title 占位符的描述在 这里。
二维数组还有一种变形就是数组包含对象(和接下来介绍的模板字符串语法很像):
describe("addition calculator", () => {
it.each([
{ x: 0, y: 0, result: 0 },
{ x: -1, y: -2, result: -3 },
{ x: 1, y: 2, result: 3 },
{ x: 8, y: 2, result: 10 }
])(
`$x plus $y equals $result`,
({ x, y, result }) => {
expect(add(x, y)).toBe(result);
}
);
});
分析了二维数组,一维数组包对象相信你也能明白了,结合对象的特点你需要注意的有两点:
- test title 的占位符由
%i
的形式改成了$x
。 - test fn 的参数使用的是解构。
参数化测试——模板字符串语法
each 除了支持数组还支持模板字符串的写法,写法如下:
describe("addition calculator", () => {
it.each`
x | y | result
${0} | ${0} | ${0}
${-1} | ${-2} | ${-3}
${1} | ${2} | ${3}
${2} | ${8} | ${10}
`(
`$x plus $y equals $result`,
({x, y, result}) => {
expect(add(x, y)).toBe(result);
}
);
});
这个模板语法首先会翻译成对象,然后它的语法注意点以及使用和上面的数组包含对象完全相同。
参数化测试——支持的 API
Jest 的 it/test
是支持 each 的,更高一层的 describe
也是支持 each 的用法的。
你可以在 Jest API 查看所有的用法。
jest-each
Jest 对 .each
的语法支持仅在 Jest 23 及更高版本中支持,所以小于 23 版本的 Jest 无法使用参数化测试功能。
但是可以借助 jest-each 这个 npm 包,让小于 23 版本的 Jest 支持参数化测试功能。
大胆猜想,Jest 使用了jest-each 包,我们去 Jest 的 GitHub 链接验证下,点击此处——jest-jasmine2 阅读。
查验如下:
jest-each概要
今天,我们学习了当遇到非常多的逻辑重复单元测试样板,我们可以使用 Jest 的参数化测试来减少样板书写,让测试变得更加直观易读和便于维护。