iOS 7 Code Coverage – Fixed!

November 23, 2013 — 22 Comments
Code coverage ERROR: no .gcda files found

But code coverage worked on iOS 6…

Update: This workaround is no longer needed for Xcode 5.1. But if you use my XcodeCoverage scripts, see Code Coverage Fixed for Xcode 5.1

Code coverage… oy vey! Back in the days of running on iOS 6 using Xcode 4, measuring code coverage for unit tests was fairly straightforward. A set of coverage scripts I published made it easier still.

Then along came iOS 7 and Xcode 5. Coverage still worked if you continued to run on iOS 6. But on iOS 7, you’d get “ERROR: no .gcda files found” indicating that coverage data wasn’t being captured. “Well, maybe I need to switch from SenTestingKit to Apple’s new XCTest framework.” Nope, that didn’t help.

Call __gcov_flush() to write out code coverage data

But I want to call it just once, after all tests have finished.

Folks starting posting questions on the Apple Developer Forums. Apple’s answer was, “You have to call __gcov_flush() to collect coverage data with the iOS simulator.” There was no need to do this before because coverage data is also written when the app exits, which apparently used to happen at the conclusion of unit tests but “we have fixed that.”

Okay, so when do you call __gcov_flush()? The simplest way is to swizzle tearDown(). The problem with this that __gcov_flush() will be invoked after every test — for one of my projects, that’s over a thousand times! But I want to call it just once, after all tests have finished.

Test observers to the rescue

Dave MacLachlan, author of CoverStory, offers a better way, made available through Google Toolbox for Mac (GTM). SenTestingKit and XCTest both have mechanisms for test observers, which Dave puts to work. Here’s how to put his code into your tests:

  1. Get a copy of the latest GTM source code. You can get it straight from the official repository. I’ve also made a mirror on GitHub.
  2. Add UnitTesting/GTMCodeCoverageApp.h and .m to your application. Don’t put them in your test target, they belong in your application target.
    If you use XCTest, add GTM_USING_XCTEST=1 to the “Preprocessor Macros” build setting for your application target.
  3. If you use SenTestingKit, add GTMCodeCoverageTestsST.m to your test target.
    If you use XCTest, add GTMCodeCoverageTestsXC.m instead.
  4. Add GTM_IS_COVERAGE_BUILD=1 to “Preprocessor Macros” for your coverage configuration. Do this at the project level so that it goes into both the app target and the test target.

And voilà, your code coverage data is back. Thanks, Dave!

Jon Reid

Posts Twitter Facebook Google+

I'm passionate about not just improving our code, but improving the way we code.

22 responses to iOS 7 Code Coverage – Fixed!

  1. Worked like a charm. Thanks for this post =)

  2. Dear Jon

    I have the following setup:
    * StaticLibrary
    * Application that depends upon StaticLibrary
    and I would like to generate a coverage report only for StaticLibrary.

    I set up the environment as suggested above (except that my StaticLibrary target plays the role of your application target). I can generate the coverage report for StaticLibrary but using the setup above Application fails to link and I get

    Undefined symbols for architecture i386:
      "___gcov_flush", referenced from:
          -[UIApplication(GTMCodeCoverage) gtm_gcov_flush] in libStaticLibrary.a(GTMCodeCoverageApp.o)
      "_llvm_gcda_emit_arcs", referenced from:
          ___llvm_gcov_writeout in libStaticLibrary.a(SampleComponent.o)
          ___llvm_gcov_writeout in libStaticLibrary.a(StaticLibrary.o)
          ___llvm_gcov_writeout in libStaticLibrary.a(GTMCodeCoverageApp.o)
      "_llvm_gcda_emit_function", referenced from:
    ...      
    ld: symbol(s) not found for architecture i386
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

    If I set
    Generate Test Coverage File = YES
    Instrument Program Flow = YES
    for Application then it builds OK. But I would not like to mandate these settings for the application.
    Can you help me what could be wrong?

    Thanks in advance!

  3. This works perfectly, thank you!

  4. Thank you Jon Reid your post helped me :)

    Hey is there a possibility to hide or ignore the GTMCodeCoverageApp.m file in my code coverage report?

    • Even though GTMCodeCoverageApp.m gets built into the main app, I put it with my other test support files in a TestSupport folder. Then in the exclude_data() function, I exclude "TestSupport/*" and that takes care of everything in that folder.

  5. Hi ,
    for get the code coverage i have follow the step
    1)write Flush in viewController.m

    - (void)viewDidLoad{  
         __gcov_flush() ;
        [super viewDidLoad];  
    }
    -(BOOL)Hello{    
        return TRUE;
    }

    2)Make test case file.

    - (void)setUp{
        controller = [[ViewController alloc]init];
        [super setUp];
    }
    - (void)tearDown{
        __gcov_flush() ;
        [super tearDown];
    }

    -(void)testHello
    {
        if(![controller Hello])
            XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
    }

    3)Compile it .

    But here i couldn’t get correct code coverage.
    I have been written three function in Viewcontroller.m Hello(), Hello1(),Hello2()

    without unit test case ,it gives the code coverage .
    How it give the code coverage?

    Can give me idea to get correct unit test coverage as per written function ?

    Thanks,
    Mahen

  6. Having upgraded to XCode 5.1 lcov started to fail processing coverage data. It says:

    gcov: Unknown command line argument '-v'.  Try: '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/gcov -help'
    gcov: Did you mean '-a'?
    gcov: Not enough positional command line arguments specified!
    Must specify at least 1 positional arguments: See: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/gcov -help

    I assume this is because XCode 5 installed a new version of gcov and its switches and options seem to have changed.

    It seems that the old gcov was saved as gcov-4.2 so I added the –gvov-tool switch to the lcov command line in getcov.sh but all I could get was an empty coverage report.

    Have you bumped in the same issue?

    Do you have a solution for this?

    Thanks in advance.

  7. Hi,

    I’ve followed through the tutorial (both this and ‘How to Measure Code Coverage’). Adding Google’s toolkit seems to result in this error:

    Undefined symbols for architecture i386:
      "___gcov_flush", referenced from:
          -[GTMCodeCoverageTests stopObserving] in GTMCodeCoverageTestsXC.o
    ld: symbol(s) not found for architecture i386
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

    can anyone advise?

    • Dave, it looks like you haven’t enabled code coverage for your build configuration. Make sure to enable “Generate Test Coverage Files” and “Instrument Program Flow”.

      We don’t need the GTM workaround anymore with Xcode 5.1 — but you’ll still need those flags for coverage.

  8. Hi,

    I am a test engineer and I am trying to do code coverage for an iOS application. I am using XCode 5.0.2 and gcovr 3.1 to test and perform code coverage for iOS 7 devices. I initially had issues with .gcda file generation issue. I followed your blog and resolved the same.

    I have set ‘Generate test coverage files’ to ‘Yes’, ‘Instrument Program flow’ to ‘Yes’ for the Debug module only. I have also set ‘ -fprofile-arcs -ftest-coverage’ for Debug module in ‘Other C Flags’. I have added ‘__gcov_flush()’ in my app code when application terminates.

    Now .gcda files are generating without issues. I copy that to my workspace in Home directory. From that location, I try to run code coverage for the application. I execute the gcovr command mentioning –object-directory and gcov command runs. I am getting “Gathered coveraged data for 0 files” at the end.

    Kindly help me to resolve the same.

Leave a Reply

*

Text formatting is available via select HTML.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> 

Have you Subscribed yet? Don't miss a post!