Microsoft MVP성태의 닷넷 이야기
Team Foundation Server: 41. 빌드 스크립트에 Code Coverage 추가 [링크 복사], [링크+제목 복사]
조회: 20894
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)
빌드 스크립트에 Code Coverage 추가

비록 Symbol/Source 서버 구성 및 형상관리 시스템의 도입이 S/W 개발에 도움이 되긴 해도, 품질 향상을 위한 별도의 작업들이 병행되어야 한다는 점에는 이견이 없을 것입니다. Visual Studio 2010의 경우, 다음과 같은 작업들이 IDE 내에서 간편하게 제공이 되는데요.

  • 단위 테스트(Unit Test)
  • 코드 커버리지(Code Coverage)
  • Code Metrics
  • 정적 코드 분석(Static Code Analysis)

이 중에서 "Code Metrics"만 명령행에서 제어가 안됩니다. 즉, LOC(Lines of Code), Cyclomatic Complexity, Class Coupling 등의 관리 정보들이 자동화될 수 없다는 점인데... 잠깐 검사를 해보니, "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies" 폴더의 "MetricsPackage.dll"에 모든 구현이 포함되어 있는데 Visual Studio IDE와 너무 밀착되어 있어서 Reflection으로도 실행하기가 쉽지 않아 보였습니다. (이 때문에 "Code Metrics" 관련 정보만큼은 별도의 다른 도구를 이용하셔야 합니다.)

혹시나, 저처럼 "Code Metrics" 기능이 명령행으로 나오기를 원하신다면, 아래의 connect 사이트에 가서 투표에 동참해주시기 바랍니다. ^^

Expose code metrics via public API and msbuild tasks 
; https://connect.microsoft.com/VisualStudio/feedback/details/497493/expose-code-metrics-via-public-api-and-msbuild-tasks

예전에 VSTS 2008 때에도 위와 같은 요청이 있었는데, 그때는 "Code Metrics" 기능이 제품 개발 말기에 급하게 구현된 것이라서 여력이 없었다는 설명을 본적 있는데,,, VS 2010에서도 구현되지 않았다는 것은 좀 문제가 있어 보입니다. ^^




제목에서와 같이, 이번 작업은 빌드 스크립트에 "코드 커버리지" 기능을 추가하는 것입니다. 이를 위해 지난번에 만들어 둔 빌드 스크립트 및 테스트 프로젝트를 대상으로 이어서 진행합니다.

배치 파일로 팀 빌드 구성
; https://www.sysnet.pe.kr/2/0/905

예제 다운로드
; https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?wid=905&boardid=331301885
(만약 TFS가 없다면, 배치 파일에서 "tf.exe" 실행 부분만 적절하게 제거하시면 됩니다.)

코드 커버리지에 대한 기능 및 그것을 명령행에서 실행하는 방법은 다음에서 자세히 설명해 주고 있습니다.

Code Coverage Basics with Visual Studio Team System
; https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/dd299398(v=vs.90)

TN_1203: Code Coverage Basics from the IDE
; http://msdn.microsoft.com/en-us/vstudio/aa718857.aspx

Use code coverage to determine how much code is being tested
; https://learn.microsoft.com/en-us/visualstudio/test/using-code-coverage-to-determine-how-much-code-is-being-tested

빌드 스크립트에 이 기능을 추가하기에 앞서 고려할 것이 있는데요. 바로 "instrumentation"을 위해서 대상 DLL 및 PDB 파일이 변조된다는 점입니다. 이 때문에, 빌드 스크립트에서 심벌 서버에 원본 PDB 파일들을 저장한 후 ~ 코드 서명을 하기 전의 중간 단계에서 바이너리 파일들을 코드 커버리지를 위해서 별도로 복사해 두어야 합니다.

여기서는, "Test"라는 별도의 폴더를 만들어서 보관한다고 가정하고 다음과 같이 스크립트를 추가합니다.

REM ======== Symbol Server

symstore ...[생략]...

REM ======== For Code Coverage
robocopy %SOLUTIONDIR%\bin\%BUILDCONFIG% .\Test

REM ======== Code Signing

signtool ...[생략]...

다음으로, 본격적으로 코드 커버리지를 수행해야 하는데, 이를 위해 "테스트 프로젝트"를 추가합니다. 즉, 여러분들이 만든 코드를 "사용하는 코드"를 만들어 두어야 한다는 것인데요. 이 방법으로는 흔히들 알고 있는 [TestClass], [TestMethod] 등의 특성을 적용한 단위 테스트를 실행할 수도 있고 별도의 EXE를 만들어두고 "Generic test"로 수행하는 방법도 있습니다.

여기서는 "Generic Test"를 이용한 EXE 실행을 해볼 텐데요. 예제 솔루션에 포함된 "TestLibrary"라는 DLL 프로젝트가 코드 커버리지 대상이고, 각각 "CodeCoverageSample1.exe"와 "CodeCoverageSample2.exe"라는 테스트용 EXE 프로젝트를 생성하여 "TestLibrary"를 사용하도록 할 것입니다.

이를 위해, 우선 다음과 같이 "TestLibrary"를 참조하는 2개의 프로젝트를 추가하고,

how_to_integrate_code_coverage_into_buildscript_1.png

빌드 스크립트에서 이 프로젝트들에 대한 빌드를 추가하고, 빌드된 결과물을 ".\Test" 폴더에 복사합니다.

REM ======== Build Test Projects

msbuild %SOLUTIONDIR%\QTesting\CodeCoverageSample1\CodeCoverageSample1.csproj /property:Platform=%TARGET_PLATFORM%;Configuration=%BUILDCONFIG%;
msbuild %SOLUTIONDIR%\QTesting\CodeCoverageSample2\CodeCoverageSample2.csproj /property:Platform=%TARGET_PLATFORM%;Configuration=%BUILDCONFIG%;

robocopy %SOLUTIONDIR%\QTesting\CodeCoverageSample1\bin\%BUILDCONFIG% .\Test
robocopy %SOLUTIONDIR%\QTesting\CodeCoverageSample2\bin\%BUILDCONFIG% .\Test

자, 이제 모든 바이너리들이 준비가 되었으니 코드 커버리지 도구를 명령행에서 수행합니다.

REM ======== Do Code Coverage

vsinstr -coverage .\Test\TestLibrary.dll

Start vsperfmon -coverage -output:TestLibrary.%GLOBAL_VERSION%.coverage

mstest ...[Generic Test를 이용한 CodeCoverageSample1.exe 실행]...
mstest ...[Generic Test를 이용한 CodeCoverageSample2.exe 실행]...

vsperfcmd -shutdown

"vsinstr -coverage" 명령행에 의해 TestLibrary.dll에 코드 커버리지를 위한 IL 코드가 삽입됩니다. 그런 후, vsperfmon.exe를 실행해 둔 상태에서 "mstest.exe"를 이용하여 "Generic Test"를 수행해 주면 정상적으로 코드 커버리지 결과파일이 생성됩니다.

주의할 것은, mstest.exe가 아닌 그냥 대상 exe 파일(예: CodeCoverageSample1.exe)을 직접 수행하는 경우 exe 실행들 간에 코드 커버리지 결과가 병합되지 않고 마지막 실행 파일 기준으로 덮어쓰기가 됩니다.

exe를 감싼 Generic Test를 만드는 방법은 다음의 글에 자세히 소개되어 있습니다.

Visual Studio 2010 Code Coverage Testing in 10 Easy Steps
; http://www.buffington.com/Blog/post/2010/04/27/Visual-Studio-2010-Code-Coverage-Testing-in-10-Easy-Steps.aspx

위의 글에서는 Visual Studio 내부의 테스트 도구에 통합하기 때문에 "*.testsettings" 파일까지 편집하게 되는데, 이 글에서는 명령행에서 직접 실행하는 것이기 때문에 "*.testsettings" 파일까지는 굳이 필요하지 않습니다. 따라서, 단순히 다음과 같이 더미 프로젝트를 하나 만들고 그 안에 "GenericTest1.GenericTest", "GenericTest2.GenericTest"를 만들어 둔 후 각각 CodeCoverageSample1.exe, CodeCoverageSample2.exe를 가리키도록 합니다.

how_to_integrate_code_coverage_into_buildscript_2.png

사실, "*.GenericTest" 파일들은 단순 XML 텍스트 파일이기 때문에 빌드 과정도 필요없습니다. (Generic Test 규격에 맞는 XML 파일을 요구되는 시점에 임의로 생성해서 사용해도 무방합니다.)

이렇게 해서 빌드 스크립트를 확장하면,

REM ======== Do Code Coverage

vsinstr ...

Start ...

mstest /testcontainer:%SOLUTIONDIR%\QTesting\GenericTest1.CodeCoverageSample1\GenericTest1.GenericTest
mstest /testcontainer:%SOLUTIONDIR%\QTesting\GenericTest1.CodeCoverageSample1\GenericTest2.GenericTest

vsperfcmd ...

자... 이렇게 해서, build.bat 파일을 실행하면 "TestLibrary.1.0.86.0.coverage"와 같은 식으로 결과 파일이 생성됩니다. 아쉽게도 이 파일은 바이너리 유형인데다, 단일 파일로는 의미가 없고 반드시 "코드 커버리지" 대상 빌드 결과물인 PDB/DLL/EXE 등의 파일들이 함께 있어야 정상적으로 Visual Studio IDE 내에서 읽혀져 코드 추적이 가능해집니다.

이런 식이라면, "자동화" 한 것에 대한 노력의 가치가 좀 떨어지죠. 이 때문에, 명령행에서 "*.coverage" 파일들에 대한 내용을 해석 가능한 XML 파일로 변환해 주는 도구가 필요한데, 다음의 글에서 배포되는 "CodeCoverageExporter" 프로젝트가 그래서 필요하게 됩니다.

Visual Studio 2010 - Code Coverage 결과를 외부 XML 파일로 출력하는 명령행 도구 제작
; https://www.sysnet.pe.kr/2/0/925

그럼, 마지막 마무리를 위해 다음과 같이 추가해 주면 완벽해지겠군요. ^^

REM ======== Do Code Coverage

vsinstr ...

Start ...

mstest ...
mstest ...

vsperfcmd ...

CodeCoverageExporter.exe .\Test .\Test TestLibrary.%GLOBAL_VERSION%.coverage TestLibrary.%GLOBAL_VERSION%.coverage.xml




한 가지 알아둬야 할 사항이 있는데요. 코드 커버리지를 위한 테스트 실행 파일의 x86/x64 빌드에 따라서 vsperfcmd.exe도 그에 알맞는 버전으로 실행해 줘야 합니다. 만약 이것이 맞지 않게 되면 "*.coverage" 파일이 생성만 될 뿐 내용은 없습니다.

vsperfcmd.exe는 x86/x64에 따라 다음과 같이 구분되어 제공됩니다.

x86: C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Performance Tools
x64: C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Performance Tools\x64

참고로, x64용 vsperfcmd.exe는 Visual Studio 2010에서 새로 추가된 기능이죠. ^^

Visual Studio 2010 x64 code coverage
; http://blogs.msdn.com/b/hilliao/archive/2010/06/18/visual-studio-2010-x64-code-coverage.aspx

여기까지의 과정을 실습한 프로젝트 및 빌드 스크립트 배치 파일을 첨부합니다. (vsperfcmd.exe가 x64용으로 잡혀 있습니다.)



[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/28/2023]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2014-07-28 05시12분
정성태

[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13602정성태4/20/2024220닷넷: 2244. C# - PCM 오디오 데이터를 연속(Streaming) 재생 (Windows Multimedia)파일 다운로드1
13601정성태4/19/2024257닷넷: 2243. C# - PCM 사운드 재생(NAudio)파일 다운로드1
13600정성태4/18/2024298닷넷: 2242. C# - 관리 스레드와 비관리 스레드
13599정성태4/17/2024437닷넷: 2241. C# - WAV 파일의 PCM 사운드 재생(Windows Multimedia)파일 다운로드1
13598정성태4/16/2024436닷넷: 2240. C# - WAV 파일 포맷 + LIST 헤더파일 다운로드2
13597정성태4/15/2024501닷넷: 2239. C# - WAV 파일의 PCM 데이터 생성 및 출력파일 다운로드1
13596정성태4/14/2024852닷넷: 2238. C# - WAV 기본 파일 포맷파일 다운로드1
13595정성태4/13/2024983닷넷: 2237. C# - Audio 장치 열기 (Windows Multimedia, NAudio)파일 다운로드1
13594정성태4/12/20241032닷넷: 2236. C# - Audio 장치 열람 (Windows Multimedia, NAudio)파일 다운로드1
13593정성태4/8/20241052닷넷: 2235. MSBuild - AccelerateBuildsInVisualStudio 옵션
13592정성태4/2/20241209C/C++: 165. CLion으로 만든 Rust Win32 DLL을 C#과 연동
13591정성태4/2/20241169닷넷: 2234. C# - WPF 응용 프로그램에 Blazor App 통합파일 다운로드1
13590정성태3/31/20241073Linux: 70. Python - uwsgi 응용 프로그램이 k8s 환경에서 OOM 발생하는 문제
13589정성태3/29/20241143닷넷: 2233. C# - 프로세스 CPU 사용량을 나타내는 성능 카운터와 Win32 API파일 다운로드1
13588정성태3/28/20241197닷넷: 2232. C# - Unity + 닷넷 App(WinForms/WPF) 간의 Named Pipe 통신파일 다운로드1
13587정성태3/27/20241157오류 유형: 900. Windows Update 오류 - 8024402C, 80070643
13586정성태3/27/20241304Windows: 263. Windows - 복구 파티션(Recovery Partition) 용량을 늘리는 방법
13585정성태3/26/20241096Windows: 262. PerformanceCounter의 InstanceName에 pid를 추가한 "Process V2"
13584정성태3/26/20241050개발 환경 구성: 708. Unity3D - C# Windows Forms / WPF Application에 통합하는 방법파일 다운로드1
13583정성태3/25/20241158Windows: 261. CPU Utilization이 100% 넘는 경우를 성능 카운터로 확인하는 방법
13582정성태3/19/20241421Windows: 260. CPU 사용률을 나타내는 2가지 수치 - 사용량(Usage)과 활용률(Utilization)파일 다운로드1
13581정성태3/18/20241589개발 환경 구성: 707. 빌드한 Unity3D 프로그램을 C++ Windows Application에 통합하는 방법
13580정성태3/15/20241138닷넷: 2231. C# - ReceiveTimeout, SendTimeout이 적용되지 않는 Socket await 비동기 호출파일 다운로드1
13579정성태3/13/20241494오류 유형: 899. HTTP Error 500.32 - ANCM Failed to Load dll
13578정성태3/11/20241631닷넷: 2230. C# - 덮어쓰기 가능한 환형 큐 (Circular queue)파일 다운로드1
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...