通过一个typescript的小游戏,使用单元测试实战(二)
题目:
该游戏是一个猜数字的游戏,
玩家输入4位0-9 不重复的数字,和电脑生成4位 0-9不重复的数字进行一个比较
如果位置和大小都正确, 计入A
如果数字正确,位置不正确, 计入B
返回 1A1B
环境准备:
- npm init -y
- npm install typescript
- npx tsc --init- npm i readline-sync ----一个通过终端输入数字的工具包
- npm i --save-dev @types/node## 使用 jest 测试
- npm install --save-dev jest
- npx create-jest 生成jest配置文件
- npm i --save-dev @types/jest
- npm i ts-jest -D
-修改jest配置文件 preset: "ts-jest",
1.utils函数准备
(1)生成一个min-max范围内的随机整数
function getRandomInRange(min: number, max: number): number {return Math.floor(Math.random() * (max - min + 1)) + min;
}
为了测试各种情况,我们优化一下函数
function getRandomInRange(min: number, max: number): number {if(typeof min !== "number" || typeof max !== "number") {throw new Error("min and max should be numbers");}if(min > max) {throw new Error("min should not be greater than max");}if(min === max) {return min;}if(!Number.isInteger(min) || !Number.isInteger(max)) {throw new Error("min and max should be integers");}return Math.floor(Math.random() * (max - min + 1)) + min;
}
(2)判断数组内是否有重复的数
function isRepeat(arr: number[] = []): boolean {for (let i = 0; i < arr.length; i++) {for (let j = i + 1; j < arr.length; j++) {if (arr[i] === arr[j]) {return true;}}}return false;
}
随机生成4个不重复的数 组成一个数组
function getComNum(): number[] {let num: number = 0;let comNum: number[] = [];while (true) {comNum = [];for (let i = 0; i < 4; i++) {num = getRandomInRange(0, 9);comNum.push(num);}if (!isRepeat(comNum)) {return comNum;}}
}
2.主要功能
const readline = require("readline-sync");
const { getComNum, isRepeat } = require("./utils/tools");function main(): void {// guessNum 用户输入的数字let guessNum: string;let a: number = 0; //A的个数let b: number = 0; //B的个数let change: number = 10; //猜测的机会const comNum: number[] = getComNum(); //电脑生成的 4位不重复的数字while (change) {console.log("请输入你要猜测的数字");guessNum = readline.question("");if (guessNum.length !== 4) {console.log("长度必须为4");} else if (isNaN(Number(guessNum))) {console.log("输入的数字有问题");} else {//符合要求,进行一个判断let guessNum2: string[] = [...guessNum];if (!isRepeat(guessNum2)) {//玩家输入的数字合格//开始对比电脑的数字 跟玩家输入的数字for (let i = 0; i < comNum.length; i++) {for (let j = 0; j < guessNum2.length; j++) {if (comNum[i]?.toString() === guessNum2[j]) {if (i === j) {a++;} else {b++;}}}}if (a === 4) {// 说明玩家全部猜对了,跳出循环break;} else {console.log(`${a}A${b}B`);change--;if (change !== 0) {//鼓励语句const arr: string[] = ["加油!","还差一点了!","你马上就猜中了!","很简单的,再想想!","也许你需要冷静一下",];let index = Math.floor(Math.random() * arr.length);console.log(`你还剩下${change}次机会,${arr[index]}`);}a = b = 0; //每次比对完成后,清空a和b的值}} else {console.log("你输入的数字重复了,请重新输入!");}}}//如果跳出了上面的while。说明游戏结束了if (change === 0) {console.log("很遗憾,你已经没有机会了!");console.log(`电脑生成的随机数为${comNum}`);} else {console.log("恭喜你,猜测正确,游戏结束");console.log("Tank you for playing");}
}
main();
3.效果展示
4.测试
创建__test__文件夹
(1)测试随机生成min-max整数的函数
- getRandomInRange.test.ts
const { getRandomInRange } = require('../tools');describe('生成一个min - max范围内的随机整数', () => {test('返回指定范围内的数字', () => {const min = 5;const max = 15;const randomValue = getRandomInRange(min, max);expect(randomValue).toBeGreaterThanOrEqual(min);expect(randomValue).toBeLessThanOrEqual(max);});test('当min/max为负数时', () => {const min = -10;const max = -5;const randomValue = getRandomInRange(min, max);expect(randomValue).toBeGreaterThanOrEqual(min);expect(randomValue).toBeLessThanOrEqual(max);});test('当min大于max时抛出错误', () => {const min = 15;const max = 5;expect(() => getRandomInRange(min, max)).toThrow('min should not be greater than max');});test('当min或max不是数字时抛出错误', () => {expect(() => getRandomInRange('a', 10)).toThrow('min and max should be numbers');expect(() => getRandomInRange(5, 'b')).toThrow('min and max should be numbers');});
});
(2)测试一个数组内部是否有重复
- isRepeat.test.ts
const { isRepeat } = require("../utils/tools");test("参数为string类型数组", () => {expect(isRepeat(["1", "1", "2", "3"])).toBe(true);expect(isRepeat(["1", "4", "2", "3"])).toBe(false);
});test("参数为number类型数组", () => {expect(isRepeat([1, 1, 2, 3])).toBe(true);expect(isRepeat([1, 4, 5, 6])).toBe(false);
});export {};
(3)测试随机生成的四位数字
-创建randomNum.test.ts
const { getRandomInRange } = require("../utils/tools");test("测试随机数", () => {// 得到一个 4 位数的数组const result = getRandomInRange();expect(result.length).toBe(4);expect(new Set(result).size).toBe(4);result.forEach((num: number) => {expect(num).toBeGreaterThanOrEqual(0);expect(num).toBeLessThanOrEqual(9);});
});export {};
然后: npm run test
运行测试结果
找到10-11,13-14
修改增加:
test('当min和max相等时,返回min', () => {const min = 5;const max = 5;const randomValue = getRandomInRange(min, max);expect(randomValue).toBe(min);});test('当min和max不是整数时,抛出错误', () => {const min = 5.5;const max = 15.5;expect(() => getRandomInRange(min, max)).toThrow('min and max should be integers');});
重新运行:
以上就是此次实战示例的测试过程,
注意:
实战总结:
(1)使用到的jest匹配器:
// 大于
expect(value1).toBeGreaterThan(3);
// 大于等于
expect(value1).toBeGreaterThanOrEqual(4);
// 小于
expect(value1).toBeLessThan(5);
// 小于等于
expect(value1).toBeLessThanOrEqual(4);
toThrow 测试某个函数,调用之后是否会抛出异常
(2)在 node 环境中,如果模块化使用的是 commonjs 规范,导入的时候会提示报错“无法重新声明块范围变量”。
要解决这个问题,首先在 ts 配置文件中,将 esModuleInterrop 开启为 true,该配置项用于控制是否启用 ES 模块规范的兼容性处理。
接下来在 tools.ts 文件的最后一行添加 export { } ,这一行代码会让 ts 认为这是一个 ESModule,从而不存在变量重复声明的问题。