views:

458

answers:

5

I am using VS2005 VC++ for unmanaged C++. I have VSTS and am trying to use the code coverage tool to accomplish two things with regards to unit tests:

  1. See how much of my referenced code under test is getting executed
  2. See how many methods of my code under test (if any) are not unit tested at all

Setting up the VSTS code coverage tool (see the link text) and accomplishing task #1 was straightforward. However #2 has been a surprising challenge for me. Here is my test code.

class CodeCoverageTarget
{
public:
    std::string ThisMethodRuns() {
         return "Running";
    }

    std::string ThisMethodDoesNotRun() {
        return "Not Running";
    }
};



#include <iostream>
#include "CodeCoverageTarget.h"
using namespace std;
int main()

{
    CodeCoverageTarget cct; 
    cout<<cct.ThisMethodRuns()<<endl;
}

When both methods are defined within the class as above the compiler automatically eliminates the ThisMethodDoesNotRun() from the obj file. If I move it's definition outside the class then it is included in the obj file and the code coverage tool shows it has not been exercised at all. Under most circumstances I want the compiler to do this elimination for me but for the code coverage tool it defeats a significant portion of the value (e.g. finding untested methods). I have tried a number of things to tell the compiler to stop being smart for me and compile everything but I am stumped. It would be nice if the code coverage tool compensated for this (I suppose by scanning the source and matching it up with the linker output) but I didn't find anything to suggest it has a special mode to be turned on. Am I totally missing something simple here or is this not possible with the VC++ compiler + VSTS code coverage tool?

Thanks in advance, KGB

A: 

Turn off inlining of functions. The easiest way to do this is to just compile in Debug mode.

Edit: after seeing your clarification, I find my answer is in error. Perhaps if you moved the body of the function into another section of the .h file, using the "inline" keyword?

Mark Ransom
A: 

Sorry I should have clarified that I am building debug mode with inlining and all optimization off. Besides, the code is getting removed before inlining even occurs since it's never referenced to even be considered for inlining.

+1  A: 

You could try adding a line of code to call the function only if some condition is true, and guarantee that that condition will never be true. Just make sure the compiler can't figure that out. For example,


int main(int argc, char **argv)
{
  if(argv == NULL)  // C runtime says this won't happen
    someMethodWhichIsntReallyEverCalled();
}
Adam Rosenfield
The problem I am trying to solve here is detecting functions/enthods that have already been written and were totally forgotten in the unit test. This should work but if I remember to do this I will probably remembered to unit test the function as well.Thanks!Kevin
A: 

Another option is to switch between inline and non inline functions based on your build, using .inl files, like this:

in foo.inl file:

inline std::string Foo::ThisMethodDoesNotRun()
{
    return "Not Running";
}

in foo.h:

#if !COVERAGE_BUILD
#include "foo.inl"
#endif

in foo.cpp:

#if COVERAGE_BUILD
#define inline
#include "foo.inl"
#endif
Don Neufeld
Thanks Don,We have ALOT of legacy code so trying to retrofit would be a problem.Kevin
+1  A: 

One way to ensure your functions are not discarded is to export them. You can do this by adding __declspec(dllexport) to your function declarations. It is best to wrap this in a C preprocessor macro so that you can turn it off, since it is compiler-specific and you might not want all of your builds to export symbols. Another way to export functions is to create a .DEF file.

If inlining is the problem, you might also have success with __declspec(noinline).

Is your code in a static library which is then compiled into a test EXE/DLL? The linker will automatically discard unreferenced object files that are in static libraries. Example: if the static library contains a.obj and b.obj and the EXE/DLL that you're linking it into references symbols from b.obj but not a.obj, then the contents of a.obj will not be linked into the executable or DLL. However, after re-reading your description it doesn't sound like that's what's happening here.

bk1e