开玩笑的报道在使用打字稿的单个 if 语句上表现得很奇怪

Jest coverage acts wierd on single if statements using typescript

看来 jest 无法涵盖单个 if 语句。这是我要测试的功能:

...  
load(): void {
    glob.sync('**/*.docs.json').forEach((file) => {
      const f = require(file);

      if (f.tags) this.doc.tags = f.tags;
});

我写了以下测试:

import path from 'path';

import Sample from './sample';

const mockedJsonConfigFile = __dirname + '/test.json';

jest.mock('glob', () => {
  return {
    sync: () => [mockedJsonConfigFile],
  };
});

describe('Sample test', () => {
  let sample: Sample;

  beforeAll(() => {
    sample = new Sample();
  });

  it('Should load file correctly', () => {
    const mockResolveFile = jest.spyOn(path, 'resolve');

    sample.load();

    let jsonFileCalled = false;
    // check if the json file is called
    mockResolveFile.mock.calls.forEach((c) => {
      if (typeof c == 'object' && c.includes(mockedJsonConfigFile)) {
        jsonFileCalled = true;
      }
    });

    expect(jsonFileCalled).toBeTruthy();
    expect(sample.doc.tags.length).toBe(2);
  });
});

它加载包含 object 个 2 个标签的夹具文件:

{
  "tags": ["tag1", "tag2"]
}

所以当我 运行 测试时,它告诉我第 15 行(if 语句)没有被覆盖,但我不明白为什么我的测试指定它应该在标签中包含 2 个元素数组。

有什么解决方法吗?

这并没有断言 load 的作用:

expect(sample.doc.tags.length).toBe(2);

它测试 tags 是类似数组的,但不是它的确切内容和分配它的条件。

当前 glob 模拟不适合此测试场景,因为它是无条件的。最好让 glob.sync 成为一个间谍,这样可以在不同的测试中更改实现,然后它可以模拟到 return 路径到不同的 JSON 固定装置。或者,glob.sync mock 可以与 JSON 文件保持不变,没有 fixture 文件。

可以这样测试:

jest.spyOn(glob, 'sync').mockReturnedValue([__dirname + '/test.json']);

...

const testJsonMock = { "tags": ["tag1", "tag2"] };
jest.mock(__dirname + '/test.json', () => testJsonMock);
sample.load();
expect(sample.doc.tags).toBe(testJsonMock.tags);

...

const testJsonMock = { "tags": null };
jest.mock(__dirname + '/test.json', () => testJsonMock);
sample.load();
expect(sample.doc.tags).toBeFalsy();