【问题标题】:How to share data between beforeAll / beforeEach and tests in Jest?如何在 Jest 中的 beforeAll / beforeEach 和测试之间共享数据?
【发布时间】:2020-06-13 01:16:37
【问题描述】:

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

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

【问题讨论】:

  • 我只是偶然发现了完全相同的问题/问题?这段时间你发现了吗?
  • @Vetterjack 我不知道发生了什么变化,也许是新版本的 jest 出现了,或者我们在其他地方遇到了错误,但我的问题中描述的方法现在似乎对我们有用。在过去的 4 个月里,我们正在同时对 32 名工作人员进行测试,并且没有遇到任何奇怪的问题,唯一的解释是数据混淆了,所以我猜它正在工作
  • 谢谢!我会试试看。顺便提一句。你现在用的是哪个版本的?
  • @Vetterjack 23.6.0
  • 我不清楚你说的分享是什么意思?您遇到的问题不是基于tenandId 确实被所有可能同时运行的测试共享的事实吗?您不想在每个测试中初始化const tenantId = await createNewTestTenant(); 吗?

标签: typescript async-await jestjs web-api-testing


【解决方案1】:

这对你有用吗?

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 挂钩来清理数据库

【讨论】:

猜你喜欢
  • 2023-03-25
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 2019-07-06
  • 2018-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多