{"id":3783,"date":"2012-12-09T05:05:15","date_gmt":"2012-12-09T05:05:15","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2012\/12\/09\/code-coverage-in-microsoft-test-manager-deep-dive\/"},"modified":"2022-07-21T03:39:39","modified_gmt":"2022-07-21T11:39:39","slug":"code-coverage-in-microsoft-test-manager-deep-dive","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/code-coverage-in-microsoft-test-manager-deep-dive\/","title":{"rendered":"Code Coverage in Microsoft Test Manager \u2013 Deep Dive"},"content":{"rendered":"<p><font color=\"#000000\">With the Quarterly Update1 for Visual Studio 2012, we have enabled collection of code coverage information for manual testing of ASP.Net web applications running under Internet Information Services (IIS). Testers will now be able to get data about how much code is covered as part of their manual testing effort using Microsoft Test Manager (MTM).<\/font><font color=\"#0000ff\"> <\/font><a href=\"http:\/\/blogs.msdn.com\/b\/visualstudioalm\/archive\/2012\/11\/28\/code-coverage-in-microsoft-test-manager-in-visual-studio-update-1.aspx\"><font color=\"#0000ff\">This<\/font><\/a><font color=\"#000000\"> blog post by Mike Douglas provides an overview of how code coverage in MTM works. As his post points out, there are several features and improvements that have been introduced with this update<\/font><a><font color=\"#000000\">. <\/font><\/a><font color=\"#000000\">The topics discussed in this post include the important parts of the code coverage configuration, the multi-user testing scenario and the details about the consolidated build level coverage file.<\/font><\/p>\n<p><strong><u><font color=\"#000000\">Simplified Configuration<\/font><\/u><\/strong><\/p>\n<p><font color=\"#000000\">For getting code coverage information, you need to create a StandardLab Environment by installing Test Agent on your web server machine. The overall experience of creating an environment has been simplified greatly in Visual Studio 2012 with auto-agent installation and configuration. The user also does not need to provide any special permission to Test Agent as opposed to Visual Studio 2010 where administrative privileges were required for collecting code coverage information. <\/font><\/p>\n<p><font color=\"#000000\">Code coverage in MTM works as a diagnostic data adapter and like any other adapter you need to enable and configure it in your test settings.<\/font><\/p>\n<p><font color=\"#000000\"><img decoding=\"async\" title=\"image\" style=\"border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px\" border=\"0\" alt=\"image\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2012\/12\/6763.image_thumb_0E6FF213.png\" width=\"353\" height=\"363\" \/><\/font><\/p>\n<p><font color=\"#000000\"><img decoding=\"async\" title=\"image\" style=\"border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px\" border=\"0\" alt=\"image\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2012\/12\/1588.image_thumb_5F5D906E.png\" width=\"354\" height=\"342\" \/><\/font><\/p>\n<p><font color=\"#000000\"><\/font><\/p>\n<p><font color=\"#000000\">By default, the code coverage engine tries to instrument all the loaded assemblies for which it can find matching symbols. You can override this and specify specific assemblies that you want to include for code coverage. Also, if the symbols are not deployed alongside the product assemblies, then you\u2019ll have to specify additional folders to search for matching PDB files. These additional folders can be on a network share but make sure that the latency between the network share and the Test Agent machine is not very high as these PDBs need to be loaded for getting source related information.<\/font><\/p>\n<p><strong><u><font color=\"#000000\">Support for Multiple Users<\/font><\/u><\/strong><\/p>\n<p><a><font color=\"#000000\">Product teams <\/font><\/a><font color=\"#000000\">generally have a shared IIS server which is used by all the testers in the team for executing their test cases. Keeping this in mind, we have also added support for allowing multiple users to test simultaneously against a <\/font><a><font color=\"#000000\">web server<\/font><\/a><font color=\"#000000\"> . A typical flow with two users testing against the same environment would look something like below:<\/font><\/p>\n<ol>\n<li><font color=\"#000000\">User1 starts a manual test run against environment Env1.<\/font> <\/li>\n<li><font color=\"#000000\">Test Agent on Env1 starts a code coverage session.<\/font> <\/li>\n<li><font color=\"#000000\">Test Agent restarts all the IIS worker processes on the web server. This is required for instrumenting w3wp.exe for code coverage.<\/font> <\/li>\n<li><font color=\"#000000\">User1 continues with his testing and accesses web applications from MTM machine.<\/font> <\/li>\n<li><font color=\"#000000\">User2 starts a new manual test run against Env1.<\/font> <\/li>\n<li><font color=\"#000000\">Since there is already a test session in progress on Env1, the test settings from User2 are ignored. IIS worker processes are also not restarted this time.<\/font> <\/li>\n<li><font color=\"#000000\">User2 continues with his testing.<\/font> <\/li>\n<li><font color=\"#000000\">User1 finishes his testing.<\/font> <\/li>\n<li><font color=\"#000000\">User2 finishes his testing.<\/font> <\/li>\n<li><font color=\"#000000\">Test Agent ends the code coverage session.<\/font> <\/li>\n<\/ol>\n<p><font color=\"#000000\">Both User1 and User2 will get coverage attachment at the end of their respective runs. One important thing to note here is that even with multiple users there is only one code coverage session on the web server. When a user ends his test run, he gets all the coverage information collected till that point which means in the above flow, User1 will get coverage data for all the code executed by w3wp.exe between step 3 and step 8. Similarly User2 will get coverage data for code executed between step 3 and step 9. There will be some duplication of coverage information in this case which is exactly the problem addressed by build level coverage file introduced with this update.<\/font><\/p>\n<p><strong><u><font color=\"#000000\">Build Level Coverage Information<\/font><\/u><\/strong><\/p>\n<p><font color=\"#000000\">Code coverage is an important metric for deciding the quality of a build and so we have introduced a build level coverage file which contains consolidated code coverage information about all the runs that were published against that build. Whenever the user publishes a test run (manualautomated) with code coverage information against a build, a background job on the TFS merges coverage information from the new run with the already published runs and keeps it on the server in the form of a file. This file can be downloaded from the coverage results link on the build summary page in Visual Studio. <\/font><\/p>\n<p><font color=\"#000000\"><img decoding=\"async\" title=\"image\" style=\"border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px\" border=\"0\" alt=\"image\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2012\/12\/6355.image_thumb_3AD8D65F.png\" width=\"537\" height=\"422\" \/><\/font><\/p>\n<p><font color=\"#000000\">The background job also puts the coverage information into the TFS database which is used by the TFS warehouse for generating code coverage reports.<\/font><\/p>\n<p><font color=\"#000000\">While the code coverage warehouse functionality was present in Visual Studio 2010 as well, with QU1, we have made an important change in the way coverage information is written to the database. The coverage job no longer writes function level coverage information to the warehouse database. This is mainly for two reasons; one, it takes a lot of time to write information about each function to the database and two, it causes the database size to grow very large over time. With the build level coverage file available this information was more or less redundant and the user could always get function level coverage data from the consolidated file. The below code shows how you can download the build coverage file and get the function level information:<\/font><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <font face=\"Consolas\"><span style=\"font-family:;color:\"><font color=\"#0000ff\"><\/font><font style=\"font-size: 9.5pt\">string<\/font><\/span><\/font><font style=\"font-size: 9.5pt\"><span style=\"font-family:;color:\"> serverPath = <\/span><span style=\"font-family:;color:\"><font color=\"#0000ff\">string<\/font><\/span><span style=\"font-family:;color:\">.Format(<\/span><span style=\"font-family:;color:\"><font color=\"#2b91af\">CultureInfo<\/font><\/span><span style=\"font-family:;color:\">.InvariantCulture, <\/span><span style=\"font-family:;color:\"><font color=\"#a31515\">&#8220;\/BuildCoverage\/{0}{1}&#8221;<\/font><\/span><span style=\"font-family:;color:\">, build.BuildNumber, <\/span><\/font>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <font face=\"Consolas\"><\/font><font style=\"font-size: 9.5pt\"><span style=\"font-family:;color:\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <\/span><span style=\"font-family:;color:\"><font color=\"#0000ff\">string<\/font><\/span><span style=\"font-family:;color:\">.Format(<\/span><span style=\"font-family:;color:\"><font color=\"#2b91af\">CultureInfo<\/font><\/span><span style=\"font-family:;color:\">.InvariantCulture, <\/span><span style=\"font-family:;color:\"><font color=\"#a31515\">&#8220;.{0}.{1}.2}.coverage&#8221;<\/font><\/span><span style=\"font-family:;color:\">,<\/span><\/font>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <font face=\"Consolas\"><\/font><font style=\"font-size: 9.5pt\"><span style=\"font-family:;color:\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 buildCoverage.Configuration.BuildFlavor,buildCoverage.Configuration.BuildPlatform,<\/span><\/font>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <font face=\"Consolas\"><\/font><font style=\"font-size: 9.5pt\"><span style=\"font-family:;color:\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <\/span>buildCoverage.Configuration.Id.ToString(<\/span><span style=\"font-family:;color:\"><font color=\"#2b91af\">NumberFormatInfo<\/font><\/span><\/font><span style=\"font-family:;color:\"><font style=\"font-size: 9.5pt\">.InvariantInfo)));<\/font><\/span>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <span style=\"font-family:;color:\"><font face=\"Consolas\"><\/font><font style=\"font-size: 9.5pt\">\u00a0<\/font><\/span>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <font face=\"Consolas\"><span style=\"font-family:;color:\"><font color=\"#0000ff\"><\/font><font style=\"font-size: 9.5pt\">string<\/font><\/span><\/font><font style=\"font-size: 9.5pt\"><span style=\"font-family:;color:\"> coverageFileUrl = <\/span><span style=\"font-family:;color:\"><font color=\"#2b91af\">String<\/font><\/span><span style=\"font-family:;color:\">.Format(<\/span><span style=\"font-family:;color:\"><font color=\"#2b91af\">CultureInfo<\/font><\/span><span style=\"font-family:;color:\">.InvariantCulture, <\/span><span style=\"font-family:;color:\"><font color=\"#a31515\">&#8220;{0}\/{1}\/_api\/_build\/ItemContent?buildUri={2}&#038;path={3}&#8221;<\/font><\/span><\/font><span style=\"font-family:;color:\"><font style=\"font-size: 9.5pt\">,<\/font><\/span>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <font face=\"Consolas\"><span style=\"font-family:;color:\"><font style=\"font-size: 9.5pt\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 build.BuildServer.TeamProjectCollection.Uri.AbsoluteUri, <\/font><\/span><\/font><font style=\"font-size: 9.5pt\"><span style=\"font-family:;color:\"><font color=\"#2b91af\">Uri<\/font><\/span><\/font><span style=\"font-family:;color:\"><font style=\"font-size: 9.5pt\">.EscapeDataString(build.TeamProject),<\/font><\/span>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt;line-height: 13pt\" align=\"justify\">\n  <font face=\"Consolas\"><span style=\"font-family:;color:;line-height: 11pt\"><font color=\"#2b91af\"><\/font><font style=\"font-size: 9.5pt\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Uri<\/font><\/span><\/font><font style=\"font-size: 9.5pt\"><span style=\"font-family:;color:;line-height: 11pt\">.EscapeDataString(build.Uri.AbsoluteUri), <\/span><span style=\"font-family:;color:;line-height: 11pt\"><font color=\"#2b91af\">Uri<\/font><\/span><\/font><span style=\"font-family:;color:;line-height: 11pt\"><font style=\"font-size: 9.5pt\">.EscapeDataString(serverPath));<\/font><\/span><span style=\"font-family:;color:;line-height: 11pt\"><\/span>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <font face=\"Consolas\"><span style=\"font-family:;color:\"><font color=\"#0000ff\"><\/font><font style=\"font-size: 9.5pt\">string<\/font><\/span><\/font><font style=\"font-size: 9.5pt\"><span style=\"font-family:;color:\"> <\/span><span style=\"font-family:;color:\">localFilePath = <\/span><span style=\"font-family:;color:\"><font color=\"#a31515\">&#8220;c:Build.Coverage&#8221;<\/font><\/span><\/font><span style=\"font-family:;color:\"><font style=\"font-size: 9.5pt\">;<\/font><\/span>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <font face=\"Consolas\"><span><font style=\"font-size: 10pt\">WebClient myWebClient = <\/font><\/span><\/font><font style=\"font-size: 10pt\"><span><font color=\"#0000ff\">new<\/font><\/span><\/font><span><font style=\"font-size: 10pt\"> WebClient();<\/font><\/span>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <font face=\"Consolas\"><span style=\"font-family:;color:\"><font style=\"font-size: 10pt\">myWebClient.DownloadFile(<\/font><\/span><span style=\"font-family:;color:\"><font style=\"font-size: 9.5pt\">coverageFileUrl<\/font><\/span><span style=\"font-family:;color:\"><font style=\"font-size: 10pt\">,<\/font><\/span><span style=\"font-family:;color:\"><font style=\"font-size: 9.5pt\"> localFilePath<\/font><\/span><span style=\"font-family:;color:\"><font style=\"font-size: 10pt\">);<\/font><span><font style=\"font-size: 10pt\">\u00a0\u00a0\u00a0 <\/font><\/span><\/span><\/font><span><\/span>\n<\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt;line-height: normal\">\n  <font face=\"Consolas\"><span style=\"font-family:;color:\"><font color=\"#2b91af\"><\/font><font style=\"font-size: 9.5pt\">CoverageInfo<\/font><\/span><\/font><font style=\"font-size: 9.5pt\"><span style=\"font-family:;color:\"> firstCoverageInfo = <\/span><span style=\"font-family:;color:\"><font color=\"#2b91af\">CoverageInfo<\/font><\/span><span style=\"font-family:;color:\">.CreateFromFile(<\/span><\/font><span style=\"font-family:;color:\"><font style=\"font-size: 9.5pt\">localFilePath<\/font><span><font style=\"font-size: 9.5pt\">);<\/font><\/span><\/span>\n<\/p>\n<p><font color=\"#000000\"><\/font><\/p>\n<p><font color=\"#000000\">The <\/font><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.coverage.analysis.coverageinfo.aspx\"><font color=\"#0000ff\">CoverageInfo<\/font><\/a><font color=\"#000000\"> class contains all information required for getting module and function level data. <\/font><\/p>\n<p><font color=\"#000000\">Lastly, the CoverageInfo class now also has a public<\/font><font color=\"#0000ff\"> <\/font><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.coverage.analysis.coverageinfo.mergecoveragefiles.aspx\"><font color=\"#0000ff\">API<\/font><\/a><font color=\"#000000\"> which can be used for merging data from two coverage files into a consolidated output coverage file.<\/font><\/p>\n<p><strong><u><font color=\"#000000\">Caveats<\/font><\/u><\/strong><\/p>\n<p><font color=\"#000000\">We have tried to make the whole experience of collecting code coverage as seamless as possible but still there are a few things to be kept in mind when using code coverage in MTM:<\/font><\/p>\n<p><font color=\"#000000\">1. Code coverage itself does not require Test Agent to be run with administrative privileges but if the test settings contains other profiler based collectors like Intellitrace and Test Impact, then you need to configure Test Agent to run under an administrator account.<\/font><\/p>\n<p><font color=\"#000000\">2. In case of multiple users testing against the same environment, the settings for the second user are ignored totally. So even if the second user has not selected code coverage in his settings, he\u2019ll still get coverage data as part of his test run results.<\/font><\/p>\n<p><font color=\"#000000\">3. Make sure you do not have TFS and the Test Agent installed on the same machine as the agent restarts all the IIS worker processes at the start of the test run. TFS also has an IIS component and restarting all the worker processes will cause the server to go offline.<\/font><\/p>\n<p><font color=\"#000000\"><\/font><\/p>\n<p>This blog has been authored by <strong>Nitya Kumar Sharma<\/strong> &amp; <strong>Hardik Patel<\/strong>, developers on the Visual Studio ALM team.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>With the Quarterly Update1 for Visual Studio 2012, we have enabled collection of code coverage information for manual testing of ASP.Net web applications running under Internet Information Services (IIS). Testers will now be able to get data about how much code is covered as part of their manual testing effort using Microsoft Test Manager (MTM). [&hellip;]<\/p>\n","protected":false},"author":77,"featured_media":45953,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-3783","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"acf":[],"blog_post_summary":"<p>With the Quarterly Update1 for Visual Studio 2012, we have enabled collection of code coverage information for manual testing of ASP.Net web applications running under Internet Information Services (IIS). Testers will now be able to get data about how much code is covered as part of their manual testing effort using Microsoft Test Manager (MTM). [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/3783","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/77"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=3783"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/3783\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/45953"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=3783"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=3783"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=3783"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}