문제

MSTEST를 사용하는 경우 Visual Studio 내에서 코드 커버리지를 테스트하는 방법이 있습니까? 아니면 ncover를 사야합니까?

Ncover Enterprise는 돈의 가치가 있습니까? 또는 Microsoft가 코드 범위를 수행하기위한 내장 도구를 제공하지 않으면 오래된 베타가 충분합니까?

편집 : VS 제품에 대한 설명 및 코드 커버리지가 포함됩니다.https://www.visualstudio.com/vs/compare/

testdriven.net (http://testdriven.net/) VS 버전이 지원하지 않으면 사용할 수 있습니다.

도움이 되었습니까?

해결책

예, Team 시스템과 같은 기능을 제공하는 Visual Studio 버전이있는 경우 Visual Studio 내에서 코드 커버리지 정보를 찾을 수 있습니다. vs.net에서 단위 테스트를 설정할 때 LocalTestrun.testrunconfig 파일이 생성되어 솔루션의 일부로 추가됩니다. 이 파일을 두 번 클릭하고 대화 상자 왼쪽에서 옵션 코드 커버리지 옵션을 찾으십시오. 코드 커버리지 정보를 수집 할 어셈블리를 선택한 다음 단위 테스트를 다시 실행하십시오. 코드 적용 범위 정보가 수집되며 사용할 수 있습니다. 코드 커버리지 정보를 얻으려면 테스트 결과 창을 열고 코드 커버리지 결과 버튼을 클릭하면 결과가 포함 된 대체 창이 열립니다.

다른 팁

MSTEST에는 코드 적용 범위가 포함되어 있습니다. 적어도 VS 버전에서는 그렇습니다. 그러나, 당신은 단지 추악하고 주요 피타 인 testrunconfig에서 계측을 활성화해야합니다.

훨씬 쉬운 옵션은 사용하는 것입니다 TestDriven.net, MSTEST의 경우에도 적용 범위를 자동화 할 수 있습니다. 그리고 MSTEST 코어를 사용하기 때문에 여전히 색상화와 같은 모든 vs의 혜성을 얻을 수 있습니다 (커버 코드의 빨간색/파란색 선). 보다 여기 (스크린 캐스트 포함) 또는 이미지에 천 단어가 말하기 때문에 :

alt text
(원천: mutantdesign.co.uk)

미래의 독자를 위해 :

와우, 이것은 재미 있지 않았다. 이것이 인터넷 토지에있는 누군가를 도울 수 있기를 바랍니다.

"codecoverage.exe"의 존재는 당신이 가진 Visual Studio의 버전에 따라 다를 수 있습니다. 빌드 서버에 VS (일부 강화 버전)를 설치해야 할 수도 있습니다.

set __msTestExe=C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\MSTest.exe
set __codeCoverageExe=C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe

rem (the below is a custom C# console application, code seen below)
set __customCodeCoverageMergerExe=CoverageCoverterConsoleApp.exe

rem below exe is from https://www.microsoft.com/en-us/download/details.aspx?id=21714 
set __msXslExe=C:\MyProgFiles\MsXslCommandLine\msxsl.exe

REM the below calls will create the binary *.coverage files
"%__codeCoverageExe%" collect /output:"D:\BuildStuff\TestResults\AAA_DynamicCodeCoverage.coverage" "%__msTestExe%" /testcontainer:"D:\BuildStuff\BuildResults\My.UnitTests.One.dll" /resultsfile:"D:\BuildStuff\TestResults\My.UnitTests.One.trx"
"%__codeCoverageExe%" collect /output:"D:\BuildStuff\TestResults\BBB_DynamicCodeCoverage.coverage" "%__msTestExe%" /testcontainer:"D:\BuildStuff\BuildResults\My.UnitTests.Two.dll" /resultsfile:"D:\BuildStuff\TestResults\My.UnitTests.Two.trx"
"%__codeCoverageExe%" collect /output:"D:\BuildStuff\TestResults\CCC_DynamicCodeCoverage.coverage" "%__msTestExe%" /testcontainer:"D:\BuildStuff\BuildResults\My.UnitTests.Three.dll" /resultsfile:"D:\BuildStuff\TestResults\My.UnitTests.Three.trx"


rem below, the first argument is the new file, the 2nd through "N" args are the result-files from the three "%__codeCoverageExe%" collect above
rem this will take the three binary *.coverage files and turn them into one .xml file
"%__customCodeCoverageMergerExe%" "D:\BuildStuff\TestResults\DynamicCodeCoverage.merged.coverage.converted.xml" "D:\BuildStuff\TestResults\AAA_DynamicCodeCoverage.coverage" "D:\BuildStuff\TestResults\BBB_DynamicCodeCoverage.coverage" "D:\BuildStuff\TestResults\CCC_DynamicCodeCoverage.coverage"


"%__msXslExe%" "D:\BuildStuff\TestResults\DynamicCodeCoverage.merged.coverage.converted.xml" "D:\BuildStuff\Xsl\VSCoverageToHtml.xsl" -o "D:\BuildStuff\TestResults\CodeCoverageReport.html"

3 개의 UnitTests.dlls를 한 번의 통화로 결합 할 수도 있습니다.

REM the below calls will create the binary *.coverage files
"%__codeCoverageExe%" collect /output:"D:\BuildStuff\TestResults\ZZZ_DynamicCodeCoverage.coverage" "%__msTestExe%" /testcontainer:"D:\BuildStuff\BuildResults\My.UnitTests.One.dll" /testcontainer:"D:\BuildStuff\BuildResults\My.UnitTests.Two.dll" /testcontainer:"D:\BuildStuff\BuildResults\My.UnitTests.Three.dll" /resultsfile:"D:\BuildStuff\TestResults\My.UnitTests.AllOfThem.trx"


rem below, the first argument is the new file, the 2nd through "N" args are the result-files from the three "%__codeCoverageExe%" collect above
rem this will take the one binary *.coverage files and turn them into one .xml file
"%__customCodeCoverageMergerExe%" "D:\BuildStuff\TestResults\DynamicCodeCoverage.merged.coverage.converted.xml" "D:\BuildStuff\TestResults\ZZZ_DynamicCodeCoverage.coverage" 


"%__msXslExe%" "D:\BuildStuff\TestResults\DynamicCodeCoverage.merged.coverage.converted.xml" "D:\BuildStuff\Xsl\VSCoverageToHtml.xsl" -o "D:\BuildStuff\TestResults\CodeCoverageReport.html"

vscoveragetohtml.xsl

또한 인터넷에서 XSL을 찾았습니다. (아래 3 개의 링크는 거의 동일한 XSL입니다)

http://codetuner.blogspot.com/2011_09_01_archive.html

http://jp.axtstar.com/?page_id=258

http://codetuner.blogspot.com/2011/09/convert-mstest-code-covarage-results-in.html

앞으로도 URL이 죽는 경우에 XSL을 여기에 게시하고 있습니다. 아래 XSL을 "VSCOVERAGETOHTML.XSL"이라는 파일에 넣습니다 (위 참조).

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" indent="yes"/> 
    <xsl:template match="/" >
        <html>
            <head>

                <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"/>          

                <style type="text/css">
                    th {
                    background-color:#dcdcdc;
                    border:solid 1px #a9a9a9;
                    text-indent:2pt;
                    font-weight:bolder;
                    }
                    #data {
                    text-align: center;
                    }
                </style>

                <script language="JavaScript" type="text/javascript"  >

                    function CreateJavescript(){
                    var fileref=document.createElement('script');
                    fileref.setAttribute("type","text/javascript");
                    fileref.setAttribute("src", "script1.js");
                    document.getElementsByTagName("head")[0].appendChild(fileref);
                    }

                    function toggleDetail(control) {
                    var ctrlId = $(control).attr('Id');
                    $("tr[id='"+ctrlId +"']").toggle();
                    }                 

                </script>

                <title>Code Coverage Report</title>
            </head>
            <body onload='CreateJavescript()' >
                <h1>Code Coverage Report</h1>
                <table border="1">
                    <tr>
                        <th colspan="3"/>
                        <th>Name</th>
                        <th>Blocks Covered</th>
                        <th>Blocks Not Covered</th>
                        <th>Coverage</th>
                    </tr>
                    <xsl:apply-templates select="//CoverageDSPriv/Module" />
                </table>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="Module">
        <xsl:variable name="parentId" select="generate-id(./..)" />
        <xsl:variable name="currentId" select="generate-id(.)" />
        <tr id="{$parentId}">
            <td id="{$currentId}"      colspan="3"               onClick="toggleDetail(this)"        onMouseOver="this.style.cursor= 'pointer' ">[+]</td>
            <td>
                <xsl:value-of select="ModuleName" />
            </td>
            <td id="data">
                <xsl:value-of select="BlocksCovered" />
            </td>
            <td id="data">
                <xsl:value-of select="BlocksNotCovered" />
            </td>
            <xsl:call-template name="CoverageColumn">
                <xsl:with-param name="covered" select="BlocksCovered" />
                <xsl:with-param name="uncovered" select="BlocksNotCovered" />
            </xsl:call-template>
        </tr>
        <xsl:apply-templates select="NamespaceTable" />
        <tr id="{$currentId}-end" style="display: none;">
            <td colspan="5"/>
        </tr>
    </xsl:template>

    <xsl:template match="NamespaceTable">
        <xsl:variable name="parentId" select="generate-id(./..)" />
        <xsl:variable name="currentId" select="generate-id(.)" />
        <tr id="{$parentId}" style="display: none;">
            <td> - </td>
            <td id="{$currentId}"
                colspan="2"
                onClick="toggleDetail(this)"
                onMouseOver="this.style.cursor= 'pointer' ">[+]</td>
            <td>
                <xsl:value-of select="NamespaceName" />
            </td>
            <td id="data">
                <xsl:value-of select="BlocksCovered" />
            </td>
            <td id="data">
                <xsl:value-of select="BlocksNotCovered" />
            </td>
            <xsl:call-template name="CoverageColumn">
                <xsl:with-param name="covered" select="BlocksCovered" />
                <xsl:with-param name="uncovered" select="BlocksNotCovered" />
            </xsl:call-template>
        </tr>
        <xsl:apply-templates select="Class" />
        <tr id="{$currentId}-end" style="display: none;">
            <td colspan="5"/>
        </tr>
    </xsl:template>

    <xsl:template match="Class">
        <xsl:variable name="parentId" select="generate-id(./..)" />
        <xsl:variable name="currentId" select="generate-id(.)" />
        <tr id="{$parentId}" style="display: none;">
            <td> - </td>
            <td> - </td>
            <td id="{$currentId}"
                onClick="toggleDetail(this)"
                onMouseOver="this.style.cursor='pointer' ">[+]</td>
            <td>
                <xsl:value-of select="ClassName" />
            </td>
            <td id="data">
                <xsl:value-of select="BlocksCovered" />
            </td>
            <td id="data">
                <xsl:value-of select="BlocksNotCovered" />
            </td>
            <xsl:call-template name="CoverageColumn">
                <xsl:with-param name="covered" select="BlocksCovered" />
                <xsl:with-param name="uncovered" select="BlocksNotCovered" />
            </xsl:call-template>
        </tr>
        <xsl:apply-templates select="Method" />
        <tr id="{$currentId}-end" style="display: none;">
            <td colspan="5"/>
        </tr>
    </xsl:template>

    <xsl:template match="Method">
        <xsl:variable name="parentId" select="generate-id(./..)" />
        <tr id="{$parentId}" style="display: none;">
            <td> -</td>
            <td> - </td>
            <td> - </td>
            <td>
                <xsl:value-of select="MethodName" />
            </td>
            <td id="data">
                <xsl:value-of select="BlocksCovered" />
            </td>
            <td id="data">
                <xsl:value-of select="BlocksNotCovered" />
            </td>
            <xsl:call-template name="CoverageColumn">
                <xsl:with-param name="covered" select="BlocksCovered" />
                <xsl:with-param name="uncovered" select="BlocksNotCovered" />
            </xsl:call-template>
        </tr>
    </xsl:template>

    <xsl:template name="CoverageColumn">
        <xsl:param name="covered" select="0" />
        <xsl:param name="uncovered" select="0" />
        <td id="data">
            <xsl:variable name="percent"
                select="($covered div ($covered + $uncovered)) * 100" />
                            <xsl:attribute name="style">
                background-color:
                <xsl:choose>
                    <xsl:when test="number($percent >= 90)">#86ed60;</xsl:when>
                    <xsl:when test="number($percent >= 70)">#ffff99;</xsl:when>
                    <xsl:otherwise>#FF7979;</xsl:otherwise>
                </xsl:choose>
            </xsl:attribute>
            <xsl:if test="$percent > 0">
                <xsl:value-of select="format-number($percent, '###.##' )" />%
            </xsl:if>
            <xsl:if test="$percent = 0">
                <xsl:text>0.00%</xsl:text>
            </xsl:if>
        </td>
    </xsl:template>
</xsl:stylesheet>

다음은 도움이되는 작은 명령 줄 도구입니다.

https://www.microsoft.com/en-us/download/details.aspx?id=21714

using System;

using Microsoft.VisualStudio.Coverage.Analysis;
using System.Collections.Generic;

/* References
\ThirdPartyReferences\Microsoft Visual Studio 11.0\Microsoft.VisualStudio.Coverage.Analysis.dll
\ThirdPartyReferences\Microsoft Visual Studio 11.0\Microsoft.VisualStudio.Coverage.Interop.dll
*/

namespace MyCompany.VisualStudioExtensions.CodeCoverage.CoverageCoverterConsoleApp
{
    class Program
    {
        static int Main(string[] args)
        {
            if (args.Length < 2)
            {
                Console.WriteLine("Coverage Convert - reads VStest binary code coverage data, and outputs it in XML format.");
                Console.WriteLine("Usage:  ConverageConvert <destinationfile> <sourcefile1> <sourcefile2> ... <sourcefileN>");
                return 1;
            }

            string destinationFile = args[0];
            //destinationFile = @"C:\TestResults\MySuperMergedCoverage.coverage.converted.to.xml";

            List<string> sourceFiles = new List<string>();

            //files.Add(@"C:\MyCoverage1.coverage");
            //files.Add(@"C:\MyCoverage2.coverage");
            //files.Add(@"C:\MyCoverage3.coverage");


            /* get all the file names EXCEPT the first one */
            for (int i = 1; i < args.Length; i++)
            {
                sourceFiles.Add(args[i]);
            }

            CoverageInfo mergedCoverage;
            try
            {
                mergedCoverage = JoinCoverageFiles(sourceFiles);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error opening coverage data: {0}", e.Message);
                return 1;
            }

            CoverageDS data = mergedCoverage.BuildDataSet();

            try
            {
                data.WriteXml(destinationFile);
            }
            catch (Exception e)
            {

                Console.WriteLine("Error writing to output file: {0}", e.Message);
                return 1;
            }

            return 0;
        }

        private static CoverageInfo JoinCoverageFiles(IEnumerable<string> files)
        {
            if (files == null)
                throw new ArgumentNullException("files");

            // This will represent the joined coverage files
            CoverageInfo returnItem = null;
            string path;

            try
            {
                foreach (string sourceFile in files)
                {
                    // Create from the current file

                    path = System.IO.Path.GetDirectoryName(sourceFile);
                    CoverageInfo current = CoverageInfo.CreateFromFile(sourceFile, new string[] { path }, new string[] { path });

                    if (returnItem == null)
                    {
                        // First time through, assign to result
                        returnItem = current;
                        continue;
                    }

                    // Not the first time through, join the result with the current
                    CoverageInfo joined = null;
                    try
                    {
                        joined = CoverageInfo.Join(returnItem, current);
                    }
                    finally
                    {
                        // Dispose current and result
                        current.Dispose();
                        current = null;
                        returnItem.Dispose();
                        returnItem = null;
                    }

                    returnItem = joined;
                }
            }
            catch (Exception)
            {
                if (returnItem != null)
                {
                    returnItem.Dispose();
                }
                throw;
            }

            return returnItem;
        }
    }
}

또한 참조 :

2012 년 동적 코드 커버리지에서 코드를 사용하여 병합하는 코드 적용 파일

Visual Studio Ultimate Edition이없는 경우이 MSBuild 작업을 사용하여 코드 커버리지 보고서를 생성 할 수도 있습니다.

http://archive.msdn.microsoft.com/vscoveragetoxmltask

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top