2012-01-19 20 views
4

Visual Studio 2010とVisual BasicでMS-Testを使用します。コードカバレッジは1つの未確認のブロックとを持つラインがあることを、私に語った次の関数でコードカバレッジ:終了マーカーが赤くなるのはなぜですか(終了、終了、など)

が赤である「試してみてくださいEND」(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 

それでは、なぜこれです"End Try"は覆われていない(赤い)ブロックを示します(関数の最後に "End If"と同じことが起こります)。

私が持っているもう1つの質問:コードカバレッジ結果のさまざまな色を説明するリソースはありますか(青は明瞭ですが、黄色、暗い、明るい赤が見えました...)。

ありがとうございます!

答えて

4

シーケンス上のダニエルのポイントには、それがさらに、この見て価値が指しています。私たちはあなたがデバッグで

07 Function Method() As String 
08  Try 
09   Return "" 
10  Catch ex As Exception 
11   Return "" 
12  End Try 
13 End Function 

をやっていることを繰り返し、単純な関数を取るならば、我々は、SLは=行を開始

<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> 

(エル(私はこれのためにOpenCoverを使用しています)は、次のシーケンスポイントを獲得します=エンドライン、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 
0を見たとき

がしかしこれらのみ意味をなす)小数のオフセット

あなたがオフセット40(IL_0028)でIL命令をヒットした場合にのみ、End Try行が表示されていることが懸念されますが、作成した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 

を変更し、そのシーケンスはだから一種の緩いいずれかの方法として、今、あなたのtry/catchラインは

を覆っマーク見ることはありません

<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 

だからあなたEnd Tryが覆われるため、我々がヒットするようにし、それは(31オフセットされるライン21が必要

<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 

IL_001F)そしてわれわれが見る通り、leave.s命令はその点にジャンプするので、その線は覆われたものとしてマークされます。また、どこにでも散らばっリターンを持っている悪い習慣である理由

+0

ありがとう!それは素晴らしい説明でした:-) – habakuk

+0

あなたは大歓迎です、私はおそらくこれをブログ記事にも転記します –

0

私はMS-Testを一度も使用していませんが、「New VersionInfo()」にチェックがついていません。

2

アセンブリのPDBファイルには、元のソースコードのどの行に対応するIL命令の情報が含まれています。この情報はシーケンスポイントと呼ばれます。 コード内のすべての行が1つのシーケンスポイントに正確に対応するわけではありません。 テストカバレッジはシーケンスポイントに基づいて計算されるため、テスト中にコードが実行されたにもかかわらずコードの行が明らかになることがあります。

3

制御がその前にEnd Try行を通過する前に、それはReturn行に達して機能を終了します。したがって、(コードカバレッジに関する限り)あなたは決してその行に到達しません。この場合、問題はありません。

回避策は、そのバージョン情報を単一の一時変数に保持し、の終了後にを返すことです。推測(私はC#のではなく、VBに使用されています):さらに

Private Function GetLatestVersionInfoForAsync() 
    Dim vi As VersionInfo 
    Try 
     vi = GetLatestVersionInfo() 
    Catch ex As Exception 
     RaiseEvent UnhandledAsyncException(Me, New UnhandledExceptionEventArgs(ex, False)) 
     vi = New VersionInfo() With {.ExceptionOccoured = True, .Exception = ex} 
    End Try 
    Return vi 
End Function 
+0

だから、ハンスとダニエルの両方が正しいと私は上記の希望は説明しています。 99%のケースでは、上記のようにリターン変数を設定し、最後にそれを戻す必要があります。 – AnthonyBlake

関連する問題