开玩笑-了解describe()和it()的执行顺序

时间:2019-05-21 14:41:43

标签: javascript unit-testing jestjs

我想理解为什么每个describe()内部的所有块it()都在describe()之前运行。

这是一个CodeSandbox example,每个describeit块中都有一个日志。

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块中的日志在第一个describe块中的it()之前运行。

为什么会这样?当我们需要在该describe块中共享数据并确定其范围时,是否应该避免在代码的那部分工作,而更喜欢使用beforeAll()

1 个答案:

答案 0 :(得分:2)

运行Jest时,它将查找所有测试文件并运行每个文件。

每个测试文件在Jest提供的环境中运行,该环境包括describeitbeforeAll等全局变量。所有这些全局变量都有一个回调参数定义他们的行为。

运行测试文件时,顶层代码即会运行...包括所有顶层describe调用。

describe运行registers a test suite,然后运行its callback is called immediately时。

这与the callback is recorded but not immediately called中的itbeforeAllbeforeEach等不同。

这意味着所有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,在此期间定义测试套件以及任何beforeAllbeforeEach,{收集了{1}},it等。

收集阶段完成后,test ...

  

以在收集阶段遇到的顺序依次运行所有测试,等待每个测试完成并整理后再继续。

对于每个测试(每个在全局Jestit函数中注册的回调函数)test links together any before callbacks, the test callback itself, and any after callbacks并按顺序运行结果函数。


  

我们是否应该避免在代码的那部分做任何事情,而在需要共享和描述该描述块中的数据时更喜欢使用Jest

对于不共享的简单内容,可以将其包含在beforeAll()中:

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,因此,如果您的测试需要任何异步设置,则需要使用describe函数,您可以在其中将before的{​​{1}}返回等待:

Promise