我想了解为什么所有 block describe()
在每个 describe()
内部的 it()
之前运行。
这是一个 CodeSandbox example每个 describe
和 it
block 都有一个日志。
describe("sum A", () => {
window.innerWidth = 100;
console.log("describe A", window.innerWidth);
beforeAll(() => {
window.innerWidth = 105;
console.log("describe A before", window.innerWidth);
});
it("1. should add 1 and 2", () => {
console.log("it A1", window.innerWidth);
expect(1 + 2).toBe(3);
});
});
describe("sum B", () => {
console.log("describe B", window.innerWidth, "why does it run before it A1?");
beforeAll(() => {
window.innerWidth = 205;
console.log("describe B before", window.innerWidth);
});
it("1. should add 1 and 2", () => {
console.log("it B1", window.innerWidth);
expect(1 + 2).toBe(3);
});
});
您会注意到第二个 describe block 中的日志在第一个 describe block 内的 it()
之前运行。
为什么会这样?当我们需要在 describe block 中共享和范围数据时,我们是否应该避免在代码的那部分做任何事情而更喜欢使用 beforeAll()
?
最佳答案
当 Jest
运行时,它会查找所有测试文件并运行每个文件。
每个测试文件都在 Jest
提供的环境中运行,其中包括全局变量,如 describe
、it
、beforeAll
等等。所有这些全局变量都有一个回调参数来定义它们的行为。
当测试文件运行时,顶层代码运行...包括任何顶层 describe
调用。
当 describe
运行它时 registers a test suite , 然后 its callback is called immediately .
这与 it
、beforeAll
、beforeEach
等不同,其中 the callback is recorded but not immediately called .
这意味着所有 describe
回调函数都按照它们在测试文件中出现的顺序被深度优先调用,如这个简单示例所示:
describe('1', () => {
console.log('1');
describe('2', () => { console.log('2'); });
describe('3', () => {
console.log('3');
describe('4', () => { console.log('4'); })
describe('5', () => { console.log('5'); })
})
describe('6', () => { console.log('6'); })
})
describe('7', () => {
console.log('7');
it('(since there has to be at least one test)', () => { });
})
...按顺序记录 1
- 7
。
所有 describe
回调的初始运行称为 collection phase在此期间,定义了测试套件以及任何 beforeAll
、beforeEach
、it
、test
的所有回调,等收集起来。
收集阶段完成后,Jest
...
runs all the tests serially in the order they were encountered in the collection phase, waiting for each to finish and be tidied up before moving on.
对于每个测试(使用全局it
或test
函数注册的每个回调函数)Jest
links together any before callbacks, the test callback itself, and any after callbacks并按顺序运行生成的函数。
Should we avoid doing stuff in that part of the code and prefer using
beforeAll()
when we need to share and scope data in that describe block?
对于不共享的简单内容,将其包含在 describe
中很好:
describe('val', () => {
const val = '1';
it('should be 1', () => {
expect(val).toBe('1'); // Success!
});
});
...但是 describe
中的代码可能会导致共享数据出现问题:
describe('val', () => {
let val;
describe('1', () => {
val = '1';
it('should be 1', () => {
expect(val).toBe('1'); // FAIL! (val gets set to 2 in the second describe)
})
})
describe('2', () => {
val = '2';
it('should be 2', () => {
expect(val).toBe('2'); // Success!
})
})
});
...这可以通过使用 before
调用来修复:
describe('val', () => {
let val;
describe('1', () => {
beforeEach(() => {
val = '1';
});
it('should be 1', () => {
expect(val).toBe('1'); // Success!
})
})
describe('2', () => {
beforeEach(() => {
val = '2';
});
it('should be 2', () => {
expect(val).toBe('2'); // Success!
})
})
});
...或者简单地将数据限定到describe
:
describe('val', () => {
describe('1', () => {
const val = '1';
it('should be 1', () => {
expect(val).toBe('1'); // Success!
})
})
describe('2', () => {
const val = '2';
it('should be 2', () => {
expect(val).toBe('2'); // Success!
})
})
});
在您的示例中,您使用的是共享全局的 window.innerWidth
,因此您需要使用 before
函数,因为它不能作用于 描述
。
另请注意,您 can't return anything from a describe
因此,如果您的测试需要任何异步设置,那么您将需要使用 before
函数,您可以在其中为 Jest
返回一个 Promise
等待:
const somethingAsync = () => Promise.resolve('1');
describe('val', () => {
let val;
beforeAll(async () => {
val = await somethingAsync();
});
it('should be 1', () => {
expect(val).toBe('1'); // Success!
});
});
关于javascript - Jest - 理解 describe() 和 it() 的执行顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56240783/