» Node.js创建命令行程序grep » 2. 开发 » 2.5 编写测试

编写测试

Node.js 有几个常用测试框架,包括 JestMochaJasmine 等。

此项目使用 Jest,因为它是一个简单易用,使人心情愉悦的 JavaScript 测试框架。

describe 用于在逻辑结构中将相关测试用例组合在一起。

describe(name: string, fn: () => void): void;

beforeAllbeforeEachafterAllafterEach 函数允许在测试套件或单个测试用例之前或之后准备清理资源。 这对于执行诸如初始化变量、创建临时文件或清理资源等操作非常有用。

expect(...).toEqual(...)是一个断言语句,用于断言一个值或对象是否等于预期值。

expect(received).toEqual(expected);

安装 jest 及其 TypeScript 支持(如果尚未安装):

npm install --save-dev jest ts-jest @types/jest

更新 package.json 以使用 jest 作为自定义测试脚本,并添加 jest 配置部分:

"scripts": {
    "test": "npx jest",
    ...
},
  "jest": {
    "preset": "ts-jest",
    "testEnvironment": "node"
  }
}

test/grep.test.ts:

import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { promisify } from 'util';
import { grep, grepRecursive, grepCount, MatchResult } from '../lib/grep';

const mkdtemp = promisify(fs.mkdtemp);
const writeFile = promisify(fs.writeFile);

let tmpDir: string;

beforeAll(async () => {
  // 在所有测试之前准备资源
  tmpDir = await mkdtemp(path.join(os.tmpdir(), 'grep-test-'));
});

afterAll(() => {
  // 在所有测试之后清理资源
  // 例如,可以删除临时目录
  fs.rmSync(tmpDir, { recursive: true });
});

beforeEach(() => {
  // 在每个测试之前准备资源
});

afterEach(() => {
  // 在每个测试之后清理资源
});

describe('grep', () => {
  it('should match lines in a file', async () => {
    const filePath = path.join(tmpDir, 'single-file.txt');
    await writeFile(filePath, 'This is an example line\nThis line should not match');

    const pattern = 'example';
    const options = { ignoreCase: false, invertMatch: false };

    const result = await grep(pattern, filePath, options);

    expect(result[filePath]).toEqual([[1, 'This is an example line']]);
  });

  it('should handle invertMatch correctly', async () => {
    const filePath = path.join(tmpDir, 'single-file.txt');
    await writeFile(filePath, 'This is an example line\nThis line should not match');

    const pattern = 'example';
    const options = { ignoreCase: false, invertMatch: true };

    const result = await grep(pattern, filePath, options);

    expect(result[filePath]).toEqual([[2, 'This line should not match']]);
  });
});

describe('grepRecursive', () => {
  it('should match lines in files recursively', async () => {
    const dirPath = path.join(tmpDir, 'nested-directory');
    const filePath1 = path.join(dirPath, 'file1.txt');
    const filePath2 = path.join(dirPath, 'subdir', 'file2.txt');

    await fs.promises.mkdir(path.join(dirPath, 'subdir'), { recursive: true });
    await writeFile(filePath1, 'This is an example line');
    await writeFile(filePath2, 'Another example line');

    const pattern = 'example';
    const options = { ignoreCase: false, invertMatch: false };

    const result = await grepRecursive(pattern, dirPath, options);

    expect(result).toEqual({
      [filePath1]: [[1, 'This is an example line']],
      [filePath2]: [[1, 'Another example line']],
    });
  });

  it('should handle invertMatch correctly in recursive search', async () => {
    const dirPath = path.join(tmpDir, 'nested-directory');
    const filePath1 = path.join(dirPath, 'file1.txt');
    const filePath2 = path.join(dirPath, 'subdir', 'file2.txt');

    await fs.promises.mkdir(path.join(dirPath, 'subdir'), { recursive: true });
    await writeFile(filePath1, 'This is an example line');
    await writeFile(filePath2, 'This line should not match');

    const pattern = 'example';
    const options = { ignoreCase: false, invertMatch: true };

    const result = await grepRecursive(pattern, dirPath, options);

    expect(result).toEqual({
      [filePath1]: [],
      [filePath2]: [[1, 'This line should not match']],
    });
  });
});

describe('grepCount', () => {
  it('should count the total number of matches in the result', () => {
    const result: MatchResult = {
      'file1.txt': [[1, 'Match line 1'], [3, 'Match line 3']],
      'file2.txt': [[2, 'Match line 2']],
    };

    const count = grepCount(result);

    expect(count).toBe(3);
  });
});

运行测试:

npx jest

# 或
npm test

应该会得到如下的测试结果:

> lr_grepjs@1.0.0 test
> npx jest

 PASS  test/grep.test.ts
  grep
    ✓ should match lines in a file (10 ms)
    ✓ should handle invertMatch correctly (1 ms)
  grepRecursive
    ✓ should match lines in files recursively (3 ms)
    ✓ should handle invertMatch correctly in recursive search (3 ms)
  grepCount
    ✓ should count the total number of matches in the result (1 ms)

Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        1.63 s, estimated 2 s
Ran all test suites.

如果有错误,将获得类似下面的断言错误消息:

> npx jest

 FAIL  test/grep.test.ts
  grep
    ✕ should match lines in a file (10 ms)
    ✓ should handle invertMatch correctly (1 ms)
  grepRecursive
    ✓ should match lines in files recursively (2 ms)
    ✓ should handle invertMatch correctly in recursive search (2 ms)
  grepCount
    ✓ should count the total number of matches in the result (1 ms)

  ● grep › should match lines in a file

    expect(received).toEqual(expected) // deep equality

    - Expected  - 1
    + Received  + 1

      Array [
        Array [
          1,
    -     "This is an example line2",
    +     "This is an example line",
        ],
      ]

      40 |     const result = await grep(pattern, filePath, options);
      41 |
    > 42 |     expect(result[filePath]).toEqual([[1, 'This is an example line2']]);
         |                              ^
      43 |   });
      44 |
      45 |   it('should handle invertMatch correctly', async () => {

      at Object.<anonymous> (test/grep.test.ts:42:30)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 4 passed, 5 total
Snapshots:   0 total
Time:        1.601 s, estimated 2 s
Ran all test suites.

然后,你可以根据此错误消息修复你的代码。

上页下页