{"id":5943,"date":"2007-01-29T14:41:00","date_gmt":"2007-01-29T14:41:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vcblog\/2007\/01\/29\/using-code-coverage-to-improve-orcas-quality\/"},"modified":"2019-02-18T18:54:37","modified_gmt":"2019-02-18T18:54:37","slug":"using-code-coverage-to-improve-orcas-quality","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/using-code-coverage-to-improve-orcas-quality\/","title":{"rendered":"Using Code Coverage to Improve Orcas Quality"},"content":{"rendered":"<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Hi, my name is Ann Zhou and I&rsquo;m an SDET (Software Design Engineer in Test) tech lead on the Visual C++ Libraries team. Today I would like to share with you something that we have been doing to improve the quality of our testing in Orcas.<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">After we shipped VS2005, the Developer Division and the VC++ team decided to take a look at the quality of our engineering work. One of the criteria we chose to use is code coverage, i.e. the percentage of the code in the product that has been exercised by automated tests. There are many ways that can be used to measure code coverage, including source code line coverage, binary block coverage, etc. We chose to focus on&nbsp;binary block coverage which is the percentage of basic blocks in the binary that are exercised by automated tests. A basic block is a set of contiguous code that runs sequentially. A block <span>has exactly one entry point and one exit point.<\/p>\n<p><\/span><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">Our code coverage goal was set to 70% block coverage. You may ask, why not higher, or even 100%? This goal was set after carefully considering the variety of ways in which there might be dead or extremely difficult to hit code in binary.&nbsp; Here are just a few of the situations that would make getting higher code coverage hard:<\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">Internal helper functions or functions from another library may not be exercised fully in the binary. The rest of the blocks in those functions are dead code.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font face=\"Calibri\" size=\"3\">The virtual inheritance hierarchy could bring lots of dead code from parent classes when its child class is being used in the binary.<\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font face=\"Calibri\" size=\"3\">Some error conditions are extremely difficult to hit and hitting those code does not bring too much value to our testing.<\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font face=\"Calibri\" size=\"3\">Some compiler generated code is extremely difficult to hit.<\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font face=\"Calibri\" size=\"3\">Currently our code coverage tool only supports x86. So 64-bit specific code will be reported as uncovered even if they do.<\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font face=\"Calibri\" size=\"3\">There are some legacy code in the source base that may be difficult to factor out.<\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">At the beginning of the code coverage effort, some of our binaries had really low code coverage percentages. After almost a year of hard work, we are proud to say that we have reached the 70% block coverage goal for most of the binaries we ship. Some of them even reached 80% or above. Here are what we&rsquo;ve done in order to achieve this.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">Get rid of dead code in the binaries by examining build options. E.g. we noticed that some of our debug binaries were not built with the \/Gy compiler option, which caused the linker not able to get rid of unused functions even when the linker option \/opt:ref is used.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">Get rid of dead code in the binaries by using dynamic linking of external libraries whenever feasible.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">Get rid of dead code in the source code. Due to the long history of our source code, there are code that were written many years ago but are no longer used. We did some clean-up of our source code to get rid of those dead code. E.g. Future VC releases will not support Win9x platforms and we&rsquo;ve got rid of those code that are Win9x specific.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">For difficult-to-hit error conditions, we used some mechanism called &ldquo;error injection&rdquo; to trigger the error conditions so that we can test the behavior of our product under those error conditions. e.g. for memory allocation failure, we intercept the memory allocation routine to call another function that returns an error code indicating that the machine is out of memory.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">For functions that throw assertions under certain error conditions, we don&rsquo;t want the test to terminate whenever an assertion occurs because otherwise there would be no way to validate the test result. So we redirect the assertion pop-ups to the debug windows and use a combination of assertion flags\/counters to validate that the proper assertions occur under the error conditions.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">Of course, we wrote thousands of new tests to cover those code that were previously ignored. When doing this, we made sure that the new tests not only exercise the code, but also do the proper validation that the product is doing the right thing. If we don&rsquo;t take care of the validation part, a high code coverage number would be meaningless, or even dangerous because it would give a false sense of testing quality.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">e.g. For functions that throw assertions under certain error conditions, we don&rsquo;t want the test to terminate whenever an assertion occurs because otherwise there would be no way to validate the test result. So we redirect the assertion pop-ups to the debug windows and use a combination of assertion flags\/counters to validate that the proper assertions occur under the error conditions.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">Looking back, we found the code coverage effort was a very rewarding experience. <\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">Most importantly, high code coverage percentage gives us a high confidence that our product is well tested. <\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">The code coverage effort gives both the QA and Dev team a better and deeper understanding of our product source base because one really needs to dig into the source base in order to figure out how a particular piece of code can be exercised.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">The code coverage effort makes our source base leaner and meaner due to the removal of dead code.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">Thanks for reading. I hope you find this posting interesting. If you have any questions\/comments on this topic, feel free to post a comment in the VC Blog.<\/p>\n<p><\/font><\/font><\/span><\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hi, my name is Ann Zhou and I&rsquo;m an SDET (Software Design Engineer in Test) tech lead on the Visual C++ Libraries team. Today I would like to share with you something that we have been doing to improve the quality of our testing in Orcas. After we shipped VS2005, the Developer Division and the [&hellip;]<\/p>\n","protected":false},"author":289,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5943","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus"],"acf":[],"blog_post_summary":"<p>Hi, my name is Ann Zhou and I&rsquo;m an SDET (Software Design Engineer in Test) tech lead on the Visual C++ Libraries team. Today I would like to share with you something that we have been doing to improve the quality of our testing in Orcas. After we shipped VS2005, the Developer Division and the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/5943","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/289"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=5943"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/5943\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=5943"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=5943"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=5943"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}