javascript - Jest - 理解 describe() 和 it() 的执行顺序

标签 javascript unit-testing jestjs

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

这是一个 CodeSandbox example每个 describeit 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 提供的环境中运行,其中包括全局变量,如 describeitbeforeAll等等。所有这些全局变量都有一个回调参数来定义它们的行为。

当测试文件运行时,顶层代码运行...包括任何顶层 describe 调用。

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

这与 itbeforeAllbeforeEach 等不同,其中 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在此期间,定义了测试套件以及任何 beforeAllbeforeEachittest 的所有回调,等收集起来。

收集阶段完成后,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.

对于每个测试(使用全局ittest 函数注册的每个回调函数)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/

相关文章:

javascript - 在 NetSuite 中提交时调用 Web 服务

javascript - jQuery的$().each()排序顺序有保证吗?

javascript - .click() 在 IE11 中拒绝访问

unit-testing - Grails Controller 测试 - 动态方法的问题

visual-studio - UI 测试 Visual Studio 2012

javascript - Jest 报道不算在报道中抛出错误

javascript - 如何使用 Google WebFontLoader 通过 url 加载自定义字体

python - 用于 HTML 字符串的 pretty-print assertEqual()

reactjs - 带有同构-fetch的Sinon spy

javascript - 通天塔/Jest : Issues exporting default class