使用beforeEach修改test.each测试数据的问题及解决方法
问题描述
为了针对多个测试条件验证多个数据文件,编写了如下简化代码:
describe.each([ ['Data 1', 'd1'], ['Data 2', 'd2']])('Test group using %s with tag %s', (datafile, tag) => { let groupData = [{'id':10},{'id':20}]; let groupTag = ''; beforeEach(() => { groupTag = tag; console.log('Beginning tests for '+tag+' using '+datafile); if(tag == 'd1') groupData = [{'id':30},{'id':40}]; if(tag == 'd2') groupData = [{'id':50},{'id':60}]; console.log(JSON.stringify(groupData[0])); }); test.each(groupData)('Test case $# [tag:sandbox]', row => { console.log(groupTag+' - Running test '+row.id); expect(row.id).toBeDefined(); //example test }); });
控制台输出如下(已添加注释):
- Beginning tests for d1 using Data 1 - {"id":30} - d1 - Running test 10 **should be 30** - Beginning tests for d1 using Data 1 - {"id":30} - d1 - Running test 20 **should be 40** - Beginning tests for d2 using Data 2 - {"id":50} - d2 - Running test 10 **should be 50** - Beginning tests for d2 using Data 2 - {"id":50} - d2 - Running test 20 **should be 60**
问题分为两部分:
- 我期望用beforeEach重置test.each的数据表是否有误(即该数据表在运行时是不可变的)?
- 如何实现我想要的测试效果?
问题解答
问题1解答
没错,你的理解是对的。test.each的参数是在测试定义阶段就被解析并固定下来的,而beforeEach是在测试执行阶段才运行的。也就是说,当test.each(groupData)被声明时,groupData还是初始的[{'id':10},{'id':20}],后续beforeEach里对groupData的修改完全不会影响到test.each已经生成的测试用例,这就是为什么输出里的id还是初始值的原因。
问题2解答
要实现根据不同tag动态切换测试数据的效果,有两种实用方案:
方案1:提前在describe.each内部生成对应测试数据
把groupData的生成逻辑提前到describe.each的回调中,不需要依赖beforeEach,直接在定义test.each时就使用对应tag的数据:
describe.each([['Data 1', 'd1'], ['Data 2', 'd2']])('Test group using %s with tag %s', (datafile, tag) => { // 直接根据tag生成对应测试数据 const groupData = tag === 'd1' ? [{'id':30},{'id':40}] : [{'id':50},{'id':60}]; let groupTag = ''; beforeEach(() => { groupTag = tag; console.log('Beginning tests for '+tag+' using '+datafile); console.log(JSON.stringify(groupData[0])); }); test.each(groupData)('Test case $# [tag:sandbox]', row => { console.log(groupTag+' - Running test '+row.id); expect(row.id).toBeDefined(); // example test }); });
方案2:用函数延迟获取测试数据
如果测试数据需要在beforeEach中做更复杂的初始化(比如异步加载文件),可以把test.each的参数改成一个函数,让它在测试执行阶段才去获取最新数据:
describe.each([['Data 1', 'd1'], ['Data 2', 'd2']])('Test group using %s with tag %s', (datafile, tag) => { let groupData = [{'id':10},{'id':20}]; let groupTag = ''; beforeEach(() => { groupTag = tag; console.log('Beginning tests for '+tag+' using '+datafile); if(tag == 'd1') groupData = [{'id':30},{'id':40}]; if(tag == 'd2') groupData = [{'id':50},{'id':60}]; console.log(JSON.stringify(groupData[0])); }); // 用函数延迟获取数据,确保执行阶段拿到最新的groupData test.each(() => groupData)('Test case $# [tag:sandbox]', row => { console.log(groupTag+' - Running test '+row.id); expect(row.id).toBeDefined(); // example test }); });
修改后控制台输出会符合预期:
- Beginning tests for d1 using Data 1 - {"id":30} - d1 - Running test 30 - Beginning tests for d1 using Data 1 - {"id":30} - d1 - Running test 40 - Beginning tests for d2 using Data 2 - {"id":50} - d2 - Running test 50 - Beginning tests for d2 using Data 2 - {"id":50} - d2 - Running test 60
内容的提问来源于stack exchange,提问作者Simon Oliver
相关产品推荐
相关产品推荐

