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

问题描述 投票:9回答:1

我们使用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
});

问题是,什么是共享这些变量的最佳方式?beforeAllbeforeEach? - 上述测试如果在执行 --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
    });
});

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

typescript async-await jest web-api-testing
1个回答
0
投票

这对你有用吗?

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);
        });

你可能需要一个AfterAll钩子来清理数据库。

© www.soinside.com 2019 - 2024. All rights reserved.