安装和移除

写测试的时候你经常需要在运行测试前做一些准备工作,和在运行测试后进行一些整理工作。 Jest 提供辅助函数来处理这个问题。

为多次测试重复设置

如果你有一些要为多次测试重复设置的工作,你可以使用 beforeEachafterEach

例如,我们考虑一些与城市信息数据库进行交互的测试。 你必须在每个测试之前调用方法 initializeCityDatabase() ,同时必须在每个测试后,调用方法 clearCityDatabase()。 你可以这样做:

  1. beforeEach(() => {
  2. initializeCityDatabase();
  3. });
  4. afterEach(() => {
  5. clearCityDatabase();
  6. });
  7. test('city database has Vienna', () => {
  8. expect(isCity('Vienna')).toBeTruthy();
  9. });
  10. test('city database has San Juan', () => {
  11. expect(isCity('San Juan')).toBeTruthy();
  12. });

beforeEachafterEach 能够通过与异步代码测试 相同的方式处理异步代码 — — 他们可以采取 done 参数或返回一个 promise。 例如,如果 initializeCityDatabase() 返回解决数据库初始化时的 promise ,我们会想返回这一 promise︰

  1. beforeEach(() => {
  2. return initializeCityDatabase();
  3. });

一次性设置

在某些情况下,你只需要在文件的开头做一次设置。 如果这个通用设置是异步的,就比较麻烦,因为没办法每个用例都设置一遍,这样性能还很差。 Jest 提供 beforeAllafterAll 处理这种情况。

例如,如果 initializeCityDatabaseclearCityDatabase 都返回了 promise ,城市数据库可以在测试中重用,我们就能把我们的测试代码改成这样:

  1. beforeAll(() => {
  2. return initializeCityDatabase();
  3. });
  4. afterAll(() => {
  5. return clearCityDatabase();
  6. });
  7. test('city database has Vienna', () => {
  8. expect(isCity('Vienna')).toBeTruthy();
  9. });
  10. test('city database has San Juan', () => {
  11. expect(isCity('San Juan')).toBeTruthy();
  12. });

作用域

默认情况下,beforeAllafterAll 的块会应用到文件中的每个测试。 此外可以通过 describe 块来将测试分组。 当 beforeAllafterAll 的块在 describe 块内部时,则其只适用于该 describe 块内的测试。

比如说,我们不仅有一个城市的数据库,还有一个食品数据库。 我们可以为不同的测试做不同的设置︰

  1. // Applies to all tests in this file
  2. beforeEach(() => {
  3. return initializeCityDatabase();
  4. });
  5. test('city database has Vienna', () => {
  6. expect(isCity('Vienna')).toBeTruthy();
  7. });
  8. test('city database has San Juan', () => {
  9. expect(isCity('San Juan')).toBeTruthy();
  10. });
  11. describe('matching cities to foods', () => {
  12. // Applies only to tests in this describe block
  13. beforeEach(() => {
  14. return initializeFoodDatabase();
  15. });
  16. test('Vienna <3 veal', () => {
  17. expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
  18. });
  19. test('San Juan <3 plantains', () => {
  20. expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
  21. });
  22. });

注意顶级的beforeEach 会比 describe 中的beforeEach 执行的更早。 下面的代码也许能帮助你理解所有 hook 的执行顺序。

  1. beforeAll(() => console.log('1 - beforeAll'));
  2. afterAll(() => console.log('1 - afterAll'));
  3. beforeEach(() => console.log('1 - beforeEach'));
  4. afterEach(() => console.log('1 - afterEach'));
  5. test('', () => console.log('1 - test'));
  6. describe('Scoped / Nested block', () => {
  7. beforeAll(() => console.log('2 - beforeAll'));
  8. afterAll(() => console.log('2 - afterAll'));
  9. beforeEach(() => console.log('2 - beforeEach'));
  10. afterEach(() => console.log('2 - afterEach'));
  11. test('', () => console.log('2 - test'));
  12. });
  13. // 1 - beforeAll
  14. // 1 - beforeEach
  15. // 1 - test
  16. // 1 - afterEach
  17. // 2 - beforeAll
  18. // 1 - beforeEach
  19. // 2 - beforeEach
  20. // 2 - test
  21. // 2 - afterEach
  22. // 1 - afterEach
  23. // 2 - afterAll
  24. // 1 - afterAll

describe 和 test 块的执行顺序

Jest 会在所有真正的测试开始之前执行测试文件里所有的 describe 处理程序(handlers)。 这是在 before*after* 处理程序里面 (而不是在 describe 块中)进行准备工作和整理工作的另一个原因。 当 describe 块运行完后,,默认情况下,Jest 会按照 test 出现的顺序(译者注:原文是in the order they were encountered in the collection phase)依次运行所有测试,等待每一个测试完成并整理好,然后才继续往下走。

考虑以下示例测试文件和输出:

  1. describe('outer', () => {
  2. console.log('describe outer-a');
  3. describe('describe inner 1', () => {
  4. console.log('describe inner 1');
  5. test('test 1', () => {
  6. console.log('test for describe inner 1');
  7. expect(true).toEqual(true);
  8. });
  9. });
  10. console.log('describe outer-b');
  11. test('test 1', () => {
  12. console.log('test for describe outer');
  13. expect(true).toEqual(true);
  14. });
  15. describe('describe inner 2', () => {
  16. console.log('describe inner 2');
  17. test('test for describe inner 2', () => {
  18. console.log('test for describe inner 2');
  19. expect(false).toEqual(false);
  20. });
  21. });
  22. console.log('describe outer-c');
  23. });
  24. // describe outer-a
  25. // describe inner 1
  26. // describe outer-b
  27. // describe inner 2
  28. // describe outer-c
  29. // test for describe inner 1
  30. // test for describe outer
  31. // test for describe inner 2

通用建议

如果测试失败,第一件要检查的事就是,当仅运行这条测试时,它是否仍然失败。 To run only one test with Jest, temporarily change that test command to a test.only:

  1. test.only('this will be the only test that runs', () => {
  2. expect(true).toBe(false);
  3. });
  4. test('this test will not run', () => {
  5. expect('A').toBe('A');
  6. });

如果你有一个测试,当它作为一个更大的用例中的一部分时,经常运行失败,但是当你单独运行它时,并不会失败,所以最好考虑其他测试对这个测试的影响。 通常可以通过修改 beforeEach 来清除一些共享的状态来修复这种问题。 如果你不确定哪些分享的状态被修改了,你可以尝试在 beforeEach 打印出来看看。