我们使用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
});
问题是,分享由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
});
});
但这似乎没有任何效果。 我真的很喜欢并行运行测试,但是在文档中我找不到任何相关内容。也许我不知道我应该找什么?
答案 0 :(得分: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挂钩来清理数据库