04 jest测试框架 -- 执行顺序

1,380 阅读4分钟

describe 和 test 执行顺序

我们先构造一个测试文件 sum.spec.js,内容如下

describe("sum1测试", () => {
    console.log("sum1测试")
    test("sum1:第1个test", () => {
        console.log("sum1:第1个test")
    })
    test("sum1: 第2个test", () => {
        console.log("sum1:第2个test")
    })
})

describe("sum2测试", () => {
    console.log("sum2测试")
    test("sum2:第1个test", () => {
        console.log("sum2:第1个test")
    })
    test("sum2:第2个test", () => {
        console.log("sum2:第2个test")
    })
})

// 打印结果
// sum1测试
// sum2测试
// sum1:第1个test
// sum1:第2个test
// sum2:第1个test
// sum2:第2个test

jest执行测试文件,并不是先把每个describe中的test全部执行完,再去执行另一个describe, 而是先执行所有describe中设定的回调函数,最后再依次执行test。

如果describe中嵌套describe,也是先顺序执行所有describe中的回调,最后再执行test中的回调。

describe('describe outer', () => {
  console.log('describe outer-a');

  describe('describe inner 1', () => {
    console.log('describe inner 1');

    test('test 1', () => console.log('test 1'));
  });

  console.log('describe outer-b');

  test('test 2', () => console.log('test 2'));

  describe('describe inner 2', () => {
    console.log('describe inner 2');

    test('test 3', () => console.log('test 3'));
  });

  console.log('describe outer-c');
});

// describe outer-a
// describe inner 1
// describe outer-b
// describe inner 2
// describe outer-c
// test 1
// test 2
// test 3

beforeEach / afterEach

如果需要在每个test之前和之后执行一些任务,则可以使用beforeEach和afterEach, 比如在beforeEach中初始化一些数据,在afterEach中清除一些副作用等。

beforeEach(() => {
    console.log('beforeEach')
});

afterEach(() => {
    console.log('afterEach')
});

test('test1', () => {
    console.log('test1')
});

test('test2', () => {
    console.log('test2')
});
// 打印结果
// beforeEach
// test1
// afterEach
// beforeEach
// test2
// afterEach

beforeAll / afterAll

有时候,我们只是想在文件开头执行一次setup,文件结果执行一次teardown,这时使用beforeAll和afterAll。

beforeAll(() => {
    console.log('beforeAll')
});

afterAll(() => {
    console.log('afterAll')
});

test('test1', () => {
    console.log('test1')
});

test('test2', () => {
    console.log('test2')
});
// 打印结果
// beforeAll
// test1
// test2
// afterAll

如果要在beforeAll或者afterAll中执行异步操作,需要将异步的Promise return出去,这样jest就会 等到Promise完成再执行后续操作。

// 构造一个异步的getData
function getData(flag){
    return new Promise(((resolve, reject) => {
        setTimeout(() => {
            console.log(flag)
            resolve()
        }, 1000)
    }))
}

beforeAll(() => {
   return getData('beforeAll') // return语句是必须的
});

afterAll(() => {
   return getData('afterAll') // return语句是必须的
});

test('test1', () => {
    console.log('test1')
});

test('test2', () => {
    console.log('test2')
});
// 打印结果
// beforeAll
// test1
// test2
// afterAll

作用域

默认情况下,beforeAll、beforeEach是作用于文件内所有test语句的,而如果我们在describe组内 使用beforeAll、beforeEach,则只是作用于describe组内的test语句。

beforeAll(() => console.log('1 - beforeAll'));
afterAll(() => console.log('1 - afterAll'));
beforeEach(() => console.log('1 - beforeEach'));
afterEach(() => console.log('1 - afterEach'));

test('', () => console.log('1 - test'));

describe('Scoped / Nested block', () => {
  beforeAll(() => console.log('2 - beforeAll'));
  afterAll(() => console.log('2 - afterAll'));
  beforeEach(() => console.log('2 - beforeEach'));
  afterEach(() => console.log('2 - afterEach'));

  test('', () => console.log('2 - test'));
});

// 1 - beforeAll
// 1 - beforeEach
// 1 - test
// 1 - afterEach
// 2 - beforeAll
// 1 - beforeEach
// 2 - beforeEach
// 2 - test
// 2 - afterEach
// 1 - afterEach
// 2 - afterAll
// 1 - afterAll

全局setup

上面我们讲了如何在单个文件内的所有test执行之前或者之后执行一些代码,而如果我们想在所有测试文件执行之前执行一些文件, 则需要借助jest配置文件,配置文件详细配置我们后续讲解,本节只简单介绍全局setup相关配置。

globalSetup [string]

指定一个全局setup文件地址,这个setup文件,必须导出一个函数,该函数接受两个参数 globalConfig 和 projectConfig。 globalSetup指定的模块函数只会执行一次。

// globalSetup.js
module.exports = function (globalConfig, projectConfig){
    console.log("global setup")
    console.log(globalConfig, projectConfig)
}

修改配置文件 jest.config.js

module.exports = {
    globalSetup: '<rootDir>/globalSetup.js',
}

执行 npm run test之后我们可以看到,在对文件测试之前,打印了global setup

于此对应的还有 globalTeardown [string],在全部文件执行之后执行一次。

setupFiles [array]

setupFiles可以设置多个文件地址,这些文件通常用来配置或安装测试环境,每个setupFile会在每个测试文件 执行之前执行一次,也就是说有几个测试文件,setupFile就会执行几次,而上面提到的globalSetup只会执行一次。

在setupFile中是访问不到jest中全局变量的如 describe、test等

//setupFile.js
module.exports = function (){
    console.log('setupFile') 
}
// jest.config.js
module.exports = {
    globalSetup: '<rootDir>/globalSetup.js',
    setupFiles:['<rootDir>/setupFile.js']
}

在setupFile中访问describe会报错

//setupFile.js
module.exports = function (){
    console.log('setupFile', describe) //这时还没有定义describe 
}

setupFilesAfterEnv [array]

setupFilesAfterEnv也是定义一组js文件,在每个测试文件执行之前执行,与setupFiles相比的区别是, setupFiles是在测试框架安装之前执行的,因此访问不到describe等全部变量,而setupFilesAfterEnv是 在测试框架安装之后执行,可以访问到全局变量。 我们可以在setupFilesAfterEnv中扩展jest的匹配器。

//setup-jest.js
const matchers = require('jest-extended');
expect.extend(matchers);

afterEach(() => {
    jest.useRealTimers();
});
//jest.config.js
const config = {
  setupFilesAfterEnv: ['<rootDir>/setup-jest.js'],
};

module.exports = config;

小结

  • globalSetup中指定的文件是最先执行的,而且全局只执行一次
  • setupFiles可以指定多个文件,会在每一个test文件执行之前执行一次,执行时访问不到jest全部变量
  • setupFilesAfterEnv也可以指定多个文件,会在每一个test文件执行之前执行一次, 并且在setupFiles之后执行,执行时可以访问到jest全局变量
  • beforeAll/afterAll 会在单个文件中所有test之前与之后执行一次,如果放到describe组内,则在组内所有test之前和之后执行一次
  • beforeEach/afterEach 会在单个文件的每个test之前与之后执行一次,同样的组内定义只对组内test有效
  • 单个文件执行时所有describe会先按顺序执行,执行完成之后才会依次执行文件中的test

我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!