开玩笑的报道在使用打字稿的单个 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();
看来 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();