2012-01-19 3 views
4

Visual Studio 2010과 Visual Basic에서 MS-Test를 사용합니다. 코드 커버리지가 하나 개되지 않은 블록과 있는 라인이 있다는 것을, 나에게 말한다 다음 함수에서코드 적용 범위 : 끝 마커가 빨간색 인 이유 (끝, 끝 ...)

이 빨간색 "시도 끝에"(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"도 마찬가지입니다).

또 다른 질문은 : 코드 적용 결과 (파란색은 분명하지만 노란색, 짙은 빨간색, 밝은 빨간색을 보았습니다 ...)의 다양한 색상을 설명하는 리소스가 있습니까?

감사합니다.

답변

4

또한 Daniel의 point on sequence point에 대해서 더 자세히 살펴볼 필요가 있습니다. 우리는 간단한 기능을 가지고가는 경우에 그것은 우리가

<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 = 엘을 줄을 시작 다음 순서 포인트 (나는 이것에 대한 OpenCover을 사용하고 있습니다) 얻을 디버그에서

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

을 무엇을하고 있는지 반복 = 엔드 라인, 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 볼 때

그러나 이러한 경우에만 의미가) 소수의 오프셋 (offset)

이제는 End Try 라인을 보시면 오프 세트 40 (IL_0028)에서 IL 명령어를 쳤을 때만 히트로 표시 될 것이 우려됩니다. 그러나 IL 생성물을 보면 생산자가 어떻게 될지를 볼 수 없습니다 이상한 IL이 생성 되었기 때문에 (leave.s은 try/catch/finally 블록을 종료하는 데 사용되는 작은 점프 임) 코드를 따라 가면 항상 leave.s에 도달하여 IL_0029로 먼저 이동합니다.릴리스에서는

일리노이는

.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에서 제안한대로 코드를 변경하고 디버그로 돌아갑니다 (보통부터 적용 범위가되기 때문에)

다시 16,
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> 

포인트 우리는 21 명중 할 라인이 필요하고 31 오프셋 당신의 End Try이 적용되는 대상의 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 지침이 원본 소스 코드의 줄과 일치하는 정보가 들어 있습니다. 이 정보 조각을 시퀀스 포인트라고합니다. 코드의 모든 라인이 하나의 시퀀스 포인트와 정확하게 일치하는 것은 아닙니다. 테스트 범위는 시퀀스 포인트를 기반으로 계산되므로 테스트 중에 실행되었지만 코드의 행이 발견되지 않을 수도 있습니다.

3

제어가 그 전에 End Try 행을 통과하기 전에 Return 행에 도달하고 함수를 종료합니다. 그래서 (코드 적용에 관한 한) 당신은 그 라인에 도달하지 못합니다. 이 경우에는 문제가되지 않습니다.

해결 방법 임시 변수에 해당 VersionInfo를 저장하고 끝 시험 후에 을 반환하는 것이 좋습니다. 짐작 (나는 VB가 아닌 C#을 익숙하게 사용합니다.) :

+0

위에서 설명 바랍니다. 99 %의 경우에 위와 같이 반환 변수를 설정하고 끝에 반환해야합니다. – AnthonyBlake