[Legacy] Flushing iOS 7 Code Coverage Data

November 23, 2013 — 26 Comments

Update: Apple took this to heart, and fixed things in Xcode 5.1.

Bug or feature? “You have to call __gcov_flush() to collect coverage data with the iOS simulator.” According to Apple, this is a feature. But not if you actually want to measure your code coverage.

Code coverage ERROR: no .gcda files found

But it worked on Xcode 4 / iOS 6…

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!

Remember, this is legacy information. Apple fixed things in subsequent releases of Xcode, so we don’t need to do all this anymore.

Disclosure of Material Connection: Some of the links in the post above are “affiliate links.” This means if you click on the link and purchase the item, I will receive an affiliate commission. Regardless, I only recommend products or services I use personally and believe will add value to my readers. I am disclosing this in accordance with the Federal Trade Commission’s 16 CFR, Part 255: “Guides Concerning the Use of Endorsements and Testimonials in Advertising.”

Enjoyed this article? Sign up to get future articles by email.

Email Address:

26 responses to [Legacy] Flushing iOS 7 Code Coverage Data

  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.

  9. I see from https://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/UnitTesting/GTMCodeCoverageTestsXC.m that Xcode 6 has deprecated XCTestObserver and XCTestLog without having a replacement.

    Thoughts?

    • As per Jon’s https://twitter.com/qcoding/status/515594893373472768, this entire workaround seems to be redundant with Xcode 6.0.1.

      Start by taking out the GTM_USING_XCTEST=1 and GTM_IS_COVERAGE_BUILD=1 preprocessor macros (fortunately Xcode 6’s search now looks in your project file, not just the source files, so that’s easy).

      Nuke the DerivedData folder and re-run tests. If, like me, you get good .gcda files from that, you can remove the Google Toolbox code from your project (unless of course you’re using Google Toolbox for other reasons).

  10. How to exclude View Controller Default methods from Code Coverage.
    like ViewDidLoad,ViewWillAppear,ViewDidReceiveMemoryWarning…….

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!