我在Visual Studio 2010和Visual Basic中使用MS-Test. 在下面的函数中,代码覆盖率告诉我,有一个未经检查的块,而“结束尝试”的行是红色的(见http://lts.cr/BVvP): Private Function GetLatestVersionInfoForAs
在下面的函数中,代码覆盖率告诉我,有一个未经检查的块,而“结束尝试”的行是红色的(见http://lts.cr/BVvP):
Private Function GetLatestVersionInfoForAsync() Try Return GetLatestVersionInfo() Catch ex As Exception RaiseEvent UnhandledAsyncException(Me, New UnhandledExceptionEventArgs(ex, False)) Return New VersionInfo() With {.ExceptionOccoured = True, .Exception = ex} End Try End Function
那么,为什么这个“结束尝试”行是一个未被覆盖的(红色)块(在函数末尾同样发生在“结束如果”)?
我有另一个问题:是否有任何资源可以解释代码覆盖率结果中的不同颜色(蓝色很明显,但我看到黄色,深色和浅红色……).
谢谢!
继丹尼尔关于序列点的观点之后,值得进一步研究.如果我们采用一个简单的函数来重复你正在做的事情07 Function Method() As String 08 Try 09 Return "" 10 Catch ex As Exception 11 Return "" 12 End Try 13 End Function
在Debug中我们得到以下序列点(我正在使用OpenCover)
<SequencePoints> <SequencePoint offset="0" ordinal="0" uspid="261" vc="0" ec="32" el="7" sc="5" sl="7"/> <SequencePoint offset="1" ordinal="1" uspid="262" vc="0" ec="12" el="8" sc="9" sl="8"/> <SequencePoint offset="2" ordinal="2" uspid="263" vc="0" ec="22" el="9" sc="13" sl="9"/> <SequencePoint offset="19" ordinal="3" uspid="264" vc="0" ec="30" el="10" sc="9" sl="10"/> <SequencePoint offset="20" ordinal="4" uspid="265" vc="0" ec="22" el="11" sc="13" sl="11"/> <SequencePoint offset="40" ordinal="5" uspid="266" vc="0" ec="16" el="12" sc="9" sl="12"/> <SequencePoint offset="41" ordinal="6" uspid="267" vc="0" ec="17" el="13" sc="5" sl="13"/> </SequencePoints>
(其中sl =起始行,el =结束行,sc =起始列,ec =结束列,偏移量= IL偏移量,以十进制表示)
然而,当你看到IL时,这些才有意义
.method public static string Method () cil managed { // Method begins at RVA 0x272c // Code size 43 (0x2b) .maxstack 2 .locals init ( [0] string Method, [1] class [mscorlib]System.Exception ex ) IL_0000: nop IL_0001: nop .try { IL_0002: ldstr "" IL_0007: stloc.0 IL_0008: leave.s IL_0029 IL_000a: leave.s IL_0028 } // end .try catch [mscorlib]System.Exception { IL_000c: dup IL_000d: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception) IL_0012: stloc.1 IL_0013: nop IL_0014: ldstr "" IL_0019: stloc.0 IL_001a: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError() IL_001f: leave.s IL_0029 IL_0021: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError() IL_0026: leave.s IL_0028 } // end handler IL_0028: nop IL_0029: ldloc.0 IL_002a: ret } // end of method Module1::Method
现在您可以看到您关注的结束尝试行只会在偏移40(IL_0028)处按下IL指令时被标记为命中,但是当您查看生成的IL时,我无法看到您将如何到达那里由于产生的奇数IL(leave.s是一个小的跳转状态,用于退出try / catch / finally块),如果你按照代码看到你将总是到达一个首先跳转到IL_0029的leave.s.
在发布时,IL会发生变化
.method public static string Method () cil managed { // Method begins at RVA 0x2274 // Code size 30 (0x1e) .maxstack 2 .locals init ( [0] string Method, [1] class [mscorlib]System.Exception ex ) .try { IL_0000: ldstr "" IL_0005: stloc.0 IL_0006: leave.s IL_001c } // end .try catch [mscorlib]System.Exception { IL_0008: dup IL_0009: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception) IL_000e: stloc.1 IL_000f: ldstr "" IL_0014: stloc.0 IL_0015: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError() IL_001a: leave.s IL_001c } // end handler IL_001c: ldloc.0 IL_001d: ret } // end of method Module1::Method
序列点也是如此
<SequencePoints> <SequencePoint offset="0" ordinal="0" uspid="33" vc="0" ec="22" el="9" sc="13" sl="9"/> <SequencePoint offset="15" ordinal="1" uspid="34" vc="0" ec="22" el="11" sc="13" sl="11"/> <SequencePoint offset="28" ordinal="2" uspid="35" vc="0" ec="17" el="13" sc="5" sl="13"/> </SequencePoints>
因此,无论哪种方式你都松散,因为现在你永远不会看到标记为覆盖的尝试/捕获线
因此,让我们按照Hans的建议尝试更改您的代码并返回调试(因为这是您通常会运行覆盖的地方)
15 Function Method2() As String 16 Dim x As String 17 Try 18 x = "" 19 Catch ex As Exception 20 x = "" 21 End Try 22 Return x 23 End Function
我们再次看一下序列点
<SequencePoints> <SequencePoint offset="0" ordinal="0" uspid="268" vc="0" ec="33" el="15" sc="5" sl="15"/> <SequencePoint offset="1" ordinal="1" uspid="269" vc="0" ec="12" el="17" sc="9" sl="17"/> <SequencePoint offset="2" ordinal="2" uspid="270" vc="0" ec="19" el="18" sc="13" sl="18"/> <SequencePoint offset="17" ordinal="3" uspid="271" vc="0" ec="30" el="19" sc="9" sl="19"/> <SequencePoint offset="18" ordinal="4" uspid="272" vc="0" ec="19" el="20" sc="13" sl="20"/> <SequencePoint offset="31" ordinal="5" uspid="273" vc="0" ec="16" el="21" sc="9" sl="21"/> <SequencePoint offset="32" ordinal="6" uspid="274" vc="0" ec="17" el="22" sc="9" sl="22"/> <SequencePoint offset="36" ordinal="7" uspid="275" vc="0" ec="17" el="23" sc="5" sl="23"/> </SequencePoints>
和IL
.method public static string Method2 () cil managed { // Method begins at RVA 0x282c // Code size 38 (0x26) .maxstack 2 .locals init ( [0] string Method2, [1] string x, [2] class [mscorlib]System.Exception ex ) IL_0000: nop IL_0001: nop .try { IL_0002: ldstr "" IL_0007: stloc.1 IL_0008: leave.s IL_001f } // end .try catch [mscorlib]System.Exception { IL_000a: dup IL_000b: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception) IL_0010: stloc.2 IL_0011: nop IL_0012: ldstr "" IL_0017: stloc.1 IL_0018: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError() IL_001d: leave.s IL_001f } // end handler IL_001f: nop IL_0020: ldloc.1 IL_0021: stloc.0 IL_0022: br.s IL_0024 IL_0024: ldloc.0 IL_0025: ret } // end of method Module1::Method2
因此,对于你的End Try被覆盖,我们需要命中第21行并且偏移31(IL_001F)并且我们可以看到两个leave.s指令跳转到那一点,所以现在该行将被标记为覆盖.
汉斯和丹尼尔都是正确的,我希望上面解释了原因