如何在beforeAll/beforeEach和Jest中的测试之间共享数据?

pet*_*ter 8 async-await typescript jest web-api-testing

我们使用jest来测试我们的API并且具有非常复杂的场景.我们使用这些beforeAll函数为每个测试设置一般辅助变量,有时设置租户分离,在其他情况下,我们使用beforeEach函数为测试设置租户分离,为测试租户设置一些默认配置,...

例如,测试可能喜欢这样的东西(正如你所看到的,我们使用TypeScript来编写测试,以防万一):

let apiClient: ApiClient;
let tenantId: string;

beforeAll(async () => {
    apiClient = await getClientWithCredentials();
});

beforeEach(async () => {
    tenantId = await createNewTestTenant();
});

describe('describing complex test scenario', () => {
    it('should have some initial state', async () => {
        await checkState(tenantId);
    });

    it('should have some state after performing op1', async () =>{
        await op1(tenantId);
        await checkStateAfterOp1(tenantId);
    });

    it('should have some state after performing op2', async () =>{
        await op2(tenantId);
        await checkStateAfterOp2(tenantId);
    });

    it('should have some state after performing op1 and op2', async () =>{
        await op1(tenantId);
        await op2(tenantId);
        await checkStateAfterOp1AndOp2(tenantId);
    });

    it('the order of op1 and op2 should not matter', async () =>{
        await op2(tenantId);
        await op1(tenantId);
        await checkStateAfterOp1AndOp2(tenantId);
    });    
});

describe('another similar complex scenario', () => {
    // ... you see where this is going
});
Run Code Online (Sandbox Code Playgroud)

问题是,分享由beforeAll和初始化的变量的最佳方法是什么beforeEach?- 如果使用--runInBand选项执行上述测试,"...在当前进程中串行运行所有测试..."

但是当并行执行时,它开始随机失败,主要是指tenantId未定义.鉴于这些测试是约200个类似测试的一部分,所有测试都通过.并行取决于机器.具有8个核心/ 16个线程的构建代理只有50-60%的通过测试.我的四核CPU的同事有80%的通过测试,对于我来说,双核CPU有时只有1-2次测试失败,有时只有10次.所以显然它取决于并行度.

我发现了2个GitHub问题,人们提到了使用它this来共享上下文的可能性(不再适用)或者将所有内容封装在describe:

所以我尝试了一种非常天真的方法:

describe('tests', () => {
    let apiClient: ApiClient;
    let tenantId: string;

    beforeAll(async () => {
        apiClient = await getClientWithCredentials();
    });

    beforeEach(async () => {
        tenantId = await createNewTestTenant();
    });

    describe('describing complex test scenario', () => {
        it('should have some initial state', async () => {
            await checkState(tenantId);
        });

        it('should have some state after performing op1', async () =>{
            await op1(tenantId);
            await checkStateAfterOp1(tenantId);
        });

        it('should have some state after performing op2', async () =>{
            await op2(tenantId);
            await checkStateAfterOp2(tenantId);
        });

        it('should have some state after performing op1 and op2', async () =>{
            await op1(tenantId);
            await op2(tenantId);
            await checkStateAfterOp1AndOp2(tenantId);
        });

        it('the order of op1 and op2 should not matter', async () =>{
            await op2(tenantId);
            await op1(tenantId);
            await checkStateAfterOp1AndOp2(tenantId);
        });    
    });

    describe('another similar complex scenario', () => {
        // ... you see where this is going
    });
});
Run Code Online (Sandbox Code Playgroud)

但这似乎没有任何影响.我真的很喜欢并行运行测试,但是在文档中我找不到任何相关内容.也许我不知道我应该找什么?

lon*_*556 3

这对你有用吗?

describe('tests', () => {
    let apiClient: ApiClient;
    let tenantIds: {id: string, used: boolean}[];

    const findUnusedTenantId = () => {
      const tenant = tenantIds.find(a => !a.used);
      tenant.used = true; 
      return tenant.id
    }

    beforeAll(async () => {
        apiClient = await getClientWithCredentials();
    });

    beforeEach(async () => {
        const id = await createNewTestTenant();
        tenantIds.push({id, used: false})
    });

    describe('describing complex test scenario', () => {
        let tenantId: string
        it('should have some initial state', async () => {
            tenantId = fineUnusedTenantId();
            await checkState(tenantId);
        });

        it('should have some state after performing op1', async () =>{
            await op1(tenantId);
            await checkStateAfterOp1(tenantId);
        });

        // ...
    });
    describe('next scenario', () => {
        let tenantId: string
        it('first test', async () => {
            tenantId = fineUnusedTenantId();
            await checkState(tenantId);
        });

Run Code Online (Sandbox Code Playgroud)

你可能想要一个 afterAll 钩子来清理数据库