为什么 Istanbul / tap 代码覆盖率在每个条件路径都被覆盖时报告 switch 语句未被覆盖?
Why does Istanbul / tap code coverage report a switch statement as not covered when each conditional path is covered?
在一个 node.js 应用程序中,我有一个 class 和一个 getter 包含一个大的 switch 语句,与此相同但更大,具有未发布的产品特定值而不是, b, c, 1, 2, 3 等:
Class SomeClass () {
constructor (someVar) {
this.someProp = someVar
}
get someGetter () {
switch (this.someProp) {
case 'a':
case 'b':
return 1
case 'c':
case 'd':
case 'e':
return 2
case 'f':
return 3
case undefined:
return null
default:
return 0
}
}
}
然后我有一个这样结构的测试用例,它到达每条可能的路径:
const expectedResults = new Map(Object.entries({
a: 1,
c: 2,
f: 3,
null: null,
z: 0
}))
for (const [testCase, expected] of expectedResults) {
const someInstance = new SomeClass(testCase)
t.equal(someInstance.someGetter, expected)
}
t.end()
这让我覆盖了所有可能的路径,并且 node tap 覆盖报告中没有危险信号。
悬停,我得到一个(黄色)未覆盖的行,这是 switch 语句本身的行:示例代码中的第 6 行,行:
switch (this.someProp) {
我试过在每个 return
之后添加冗余的 break
,但是这些随后(正确地!)标记为未覆盖(因为它们无法访问)。
我想也许它在抱怨,因为它有一个测试,例如,在 returns 1
路径中的 'a'
但在同一路径中没有 'b'
.但如果那是问题所在,我不明白为什么它会标记 switch 语句本身,而不是那些特定的行。
当我让测试覆盖所有可能的 case:
,而不仅仅是每条路径时,未覆盖的行通知消失了。
由于在我的真实世界代码中有很多很多情况,并且所有 return 路径都经过测试是正确的,而不是大量扩展 expectedResults
映射,我创建了另一个,更简单的测试条件,它采用每个案例的简单数组,并简单地确保每个案例都被识别(不会回落到默认值)。喜欢:
const allCases = ['a', 'b', 'c', 'd', 'e', 'f']
for (const testCase of allCases) {
const someInstance = new SomeClass(testCase)
t.notEqual(someInstance.someGetter, 0)
}
通过与默认回退值进行比较,这个测试至少有一些价值,它不仅仅是为了满足 100% 的覆盖率:它确保 switch 中没有可能的情况在未来被删除等(例如,如果switch 语句被重新排序或修改)。
在一个 node.js 应用程序中,我有一个 class 和一个 getter 包含一个大的 switch 语句,与此相同但更大,具有未发布的产品特定值而不是, b, c, 1, 2, 3 等:
Class SomeClass () {
constructor (someVar) {
this.someProp = someVar
}
get someGetter () {
switch (this.someProp) {
case 'a':
case 'b':
return 1
case 'c':
case 'd':
case 'e':
return 2
case 'f':
return 3
case undefined:
return null
default:
return 0
}
}
}
然后我有一个这样结构的测试用例,它到达每条可能的路径:
const expectedResults = new Map(Object.entries({
a: 1,
c: 2,
f: 3,
null: null,
z: 0
}))
for (const [testCase, expected] of expectedResults) {
const someInstance = new SomeClass(testCase)
t.equal(someInstance.someGetter, expected)
}
t.end()
这让我覆盖了所有可能的路径,并且 node tap 覆盖报告中没有危险信号。
悬停,我得到一个(黄色)未覆盖的行,这是 switch 语句本身的行:示例代码中的第 6 行,行:
switch (this.someProp) {
我试过在每个 return
之后添加冗余的 break
,但是这些随后(正确地!)标记为未覆盖(因为它们无法访问)。
我想也许它在抱怨,因为它有一个测试,例如,在 returns 1
路径中的 'a'
但在同一路径中没有 'b'
.但如果那是问题所在,我不明白为什么它会标记 switch 语句本身,而不是那些特定的行。
当我让测试覆盖所有可能的 case:
,而不仅仅是每条路径时,未覆盖的行通知消失了。
由于在我的真实世界代码中有很多很多情况,并且所有 return 路径都经过测试是正确的,而不是大量扩展 expectedResults
映射,我创建了另一个,更简单的测试条件,它采用每个案例的简单数组,并简单地确保每个案例都被识别(不会回落到默认值)。喜欢:
const allCases = ['a', 'b', 'c', 'd', 'e', 'f']
for (const testCase of allCases) {
const someInstance = new SomeClass(testCase)
t.notEqual(someInstance.someGetter, 0)
}
通过与默认回退值进行比较,这个测试至少有一些价值,它不仅仅是为了满足 100% 的覆盖率:它确保 switch 中没有可能的情况在未来被删除等(例如,如果switch 语句被重新排序或修改)。