Xcode5 Code Coverage (from cmd-line for CI builds) - objective-c

How can I generate code coverage with Xcode 5 and iOS7?
Prior to upgrading I was getting code coverage just fine. Now I can't see any *.gcda files being produced.
The cmd-line that I'm using is:
xcodebuild -workspace ${module.name}.xcworkspace test -scheme ${module.name} -destination OS=${module.sdk.version},name=iPad -configuration Debug
Works with AppCode
When I execute the tests via AppCode I can see *.gcda files being produced in ~/Library/Caches/appCode20/DerivedData. . . I need this to work for my Continuous Integration builds.
Works from Xcode IDE
Also works from Xcode IDE. . . is there a cmd-line that will produce coverage, or is this an Xcode bug?

The following is a fix for SenTestKit - simply add this class to your Tests target. Something similar should be possible to do with XCTest
#interface VATestObserver : SenTestLog
#end
static id mainSuite = nil;
#implementation VATestObserver
+ (void)initialize {
[[NSUserDefaults standardUserDefaults] setValue:#"VATestObserver" forKey:SenTestObserverClassKey];
[super initialize];
}
+ (void)testSuiteDidStart:(NSNotification*)notification {
[super testSuiteDidStart:notification];
SenTestSuiteRun* suite = notification.object;
if (mainSuite == nil) {
mainSuite = suite;
}
}
+ (void)testSuiteDidStop:(NSNotification*)notification {
[super testSuiteDidStop:notification];
SenTestSuiteRun* suite = notification.object;
if (mainSuite == suite) {
UIApplication* application = [UIApplication sharedApplication];
[application.delegate applicationWillTerminate:application];
}
}
and add
extern void __gcov_flush(void);
- (void)applicationWillTerminate:(UIApplication*)application {
__gcov_flush();
}
Why is this working?
Tests and the tested application are compiled separately. Tests are actually injected into the running application, so the __gcov_flush() must be called inside the application not inside the tests.
The little magic with the observer only enables us to check when the tests are going to end and we trigger __gcov_flush() to be called inside the app.

(This is not the answer, but a work-around . . .I'm still very much interested in a better solution)
Use iOS 6.1 Simulator
If you're targeting iOS 6.1 or earlier as a deployment target, you can use the 6.1 simulator.
Install the iOS6.1 Simulator via preferences/downloads
Use the following cmd-line:
xcodebuild -workspace ${module.name}.xcworkspace test -scheme ${module.name} -destination OS=6.1,name=iPad -configuration Debug

We found that we had to add a bit of code to get the gcda files to flush from the system.
Code addition is to add
extern void __gcov_flush(); to the top of your file and then call __gcov_flush(); just before the entire test suite exits.
Full explanation is here: http://www.bubblefoundry.com/blog/2013/09/generating-ios-code-coverage-reports/

With the information from here I was able to craft this version which is the least invasive I could think of. Just add to your unit tests and run the tests as normal. The ZZZ ensures it is the last run suite of tests.
I had to ensure I added the GCC_GENERATE_TEST_COVERAGE_FILES and GCC_GENERATE_TEST_COVERAGE_FILES compiler flags to my test unit target too to get the coverage out.
//
// Created by Michael May
//
#import <SenTestingKit/SenTestingKit.h>
#interface ZZZCodeCoverageFixForUnitTests : SenTestCase
#end
#implementation ZZZCodeCoverageFixForUnitTests
// This must run last
extern void __gcov_flush();
-(void)testThatIsntReallyATest
{
NSLog(#"FLUSHING GCOV FILES");
__gcov_flush();
}
#end
Edit, or another approach by Jasper:
I stripped the VATestObserver from the other answer down to this:
#interface VATestObserver : SenTestLog
#end
#implementation VATestObserver
extern void __gcov_flush(void);
- (void)applicationWillTerminate:(UIApplication*)application
{
__gcov_flush();
[super applicationWillTerminate:application];
}
#end

Some more documentation here:
https://code.google.com/p/coverstory/wiki/UsingCoverstory
and some source code to use:
https://code.google.com/p/google-toolbox-for-mac/source/browse/#svn%2Ftrunk%2FUnitTesting
You need GTMCodeCoverageApp.h/.m and GTMCodeCoverageTestsXC.h/.m or GTMCodeCoverageTestsST.h/.m depending on if you are using XCTest or SenTest.

Update: New accepted answer
In some cases the coverage flushing needs to be done from within the app itself. The solution's outline in this question provide details.

Related

What is the proper way to detect if unit tests are running at runtime in Xcode?

When I'm running unit tests, I'd like to skip some code (e.g. I don't want [[UIApplication sharedApplication] openURL:..] to run). I'm looking for a runtime check if I'm currently running units tests or not.
I know I have seen code that checks the Objective-C runtime if unit tests are running but am not able to find it anymore.
You can use this method from google-toolbox-for-mac
// Returns YES if we are currently being unittested.
+ (BOOL)areWeBeingUnitTested {
BOOL answer = NO;
Class testProbeClass;
#if GTM_USING_XCTEST // you may need to change this to reflect which framework are you using
testProbeClass = NSClassFromString(#"XCTestProbe");
#else
testProbeClass = NSClassFromString(#"SenTestProbe");
#endif
if (testProbeClass != Nil) {
// Doing this little dance so we don't actually have to link
// SenTestingKit in
SEL selector = NSSelectorFromString(#"isTesting");
NSMethodSignature *sig = [testProbeClass methodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
[invocation setSelector:selector];
[invocation invokeWithTarget:testProbeClass];
[invocation getReturnValue:&answer];
}
return answer;
}
The reason that NSClassFromString and NSInvocation are used is to allow code compile without linking to xctest or ocunit
Rather that sprinkling "am I testing?" conditionals throughout production code, I isolate the check to one place: main. There, I check for an alternate application delegate for testing. If it's available, I use it instead of the the regular application delegate. This completely bypasses the regular launch sequence:
int main(int argc, char *argv[])
{
#autoreleasepool {
Class appDelegateClass = NSClassFromString(#"TestingAppDelegate");
if (!appDelegateClass)
appDelegateClass = [AppDelegate class];
return UIApplicationMain(argc, argv, nil, NSStringFromClass(appDelegateClass));
}
}
You can read more about this technique here: How to Easily Switch Your iOS App Delegate for Testing
Select the project, and then the test target:
Select Build Settings and choose All and Combined. Type 'preproc' in the search box - you're after Preprocessor Macros.
Add a macro to the Debug configuration called TEST and set it equal to 1:
Then in your code, you can do this:
#ifndef TEST
[[UIApplication sharedApplication] doEvilThingForTesting];
#endif
Or if you have code that you want to only run in a test environment:
#ifdef TEST
[[UIApplication sharedApplication] doAwesomeTestOnlyThing];
#endif
It's not exactly runtime, but the unit tester compiles the code before it runs the tests IIRC, so it should be the same effect - you're essentially modifying the code right before running the tests.
I'm not sure how long this will continue to work, but it works for me right now with Version 9.0 beta 6 (9M214v).
let isTesting = { () -> Bool in
if let _ = ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] {
return true
} else if let testingEnv = ProcessInfo.processInfo.environment["DYLD_INSERT_LIBRARIES"] {
return testingEnv.contains("libXCTTargetBootstrapInject.dylib")
} else {
return false
}
}()
No build environment or scheme changes are necessary.
It appears that there are two different environment variables in play depending on whether you are running a single test case or the entire test suite. Also, the variable value also differs depending whether or not you are running in simulator or on a real device.
I think you can check like this for Xcode 7.3
-(BOOL) isRunningUnitTests
{
NSDictionary* environment = [ [ NSProcessInfo processInfo ] environment ];
NSString* theTestConfigPath = environment[ #"XCTestConfigurationFilePath" ];
return theTestConfigPath != nil;
}
The easiest (and working in Xcode 7 with XCTest!) way to check is to have a look at the process info for a matching xctest bundle:
static BOOL isRunningTests(void)
{
NSDictionary* environment = [[NSProcessInfo processInfo] environment];
NSString* injectBundle = environment[#"XCInjectBundle"];
return [[injectBundle pathExtension] isEqualToString:#"xctest"];
}
Source: https://www.objc.io/issues/1-view-controllers/testing-view-controllers/#integration-with-xcode
Just use this:
+ (BOOL)isUnitTestRunning
{
Class testProbeClass;
testProbeClass = NSClassFromString(#"XCTestProbe");
return (testProbeClass != nil);
}

Getting nil value for the variable in Unit Test using XCTest

The appDelegate instance is showing nil value, test case "testAppDelegate" is getting failed.
The same is working in the sample code provided by apple developer site but there SenTestCase is being used, please help me out, even the target is set as per the WWDC 2013 video "Testing in Xcode 5 session 409"
#interface Tests : XCTestCase
{
AppDelegate *appDelegate;
AppViewController *appVC;
UIView *appView;
}
#end
#implementation Tests
- (void)setUp
{
[super setUp];
appDelegate = [[UIApplication sharedApplication] delegate];
appVC = appDelegate.appViewController;
appView = appVC.view;
}
- (void)tearDown
{
[super tearDown];
}
- (void)testAppDelegate
{
XCTAssert(appDelegate, #"Cannot find the application delegate");
}
- (void)testCheckForViewInitializatio
{
XCTAssert(appVC, #"AppViewController initialized");
}
Try this:
go to Project Settings
select your test target
in General tab switch Target section to your main target
Run again
Anton gives right suggestion.
But if it doesn't works (as in my case) try to:
Remove your existing Test Target
Create new Test Target (5-th tab in left pane -> click on + in bottom left corner -> New Test Target) and
In appeared window don't forget to choose your application as target of your test target.
Add all your TestCases files to new target.
I don't know the reason, but after this action it start working correctly, when I run tests with new target.

NSURLSession or NSURLConnection - iOS 6 support

I need to make a connection to my server to get some JSON data and I have to support both iOS 6 and iOS 7.
Should I create two classes? One with NSURLSession for iOS 7 and one with NSURLConnection for iOS 6? Or should I just use NSURLConnection for both of them?
What benefit would you gain by creating two separate classes that do essentially the same thing? If you can't use NSURLSession because it's only supported in iOS 7, and you can get the same functionality using NSURLConnection, which works in both, then just use NSURLConnection. You will have less code to maintain.
Great question. In fact I had the same question and researched it quite a bit and I think this is a good place to use a protocol (a.k.a. interface in other languages). This is based off of the quote "Program to an interface, not an implementation" from the famous "Gang of Four" Patterns Book. I think it's best to try and code for the future so I never get hammered if they decide to deprecate something (which isn't the case here, but you never know).
Instead of writing classes, write a protocol that defines the methods you want to use and then create 2 different classes that implement those methods. In your app you would make a pointer that can point to any class that implements all of that protocols methods and then each implementing class can use whatever frameworks/libraries/other code they want to make that happen.
As an example, you could create a Server protocol like this:
// Server.h
#protocol Server <NSObject>
#required
- (void)callService:(NSString *)service withData:(NSData *)data;
#end
and then create a RestServer class like this:
// RestServer.h
#import "Server.h"
#interface RestServer : NSObject <Server>
#end
// RestServer.m
#import "RestServer.h"
#implementation RestServer
- (void)callService:(NSString *)service withData:(NSData *)data {
// Code using REST
}
#end
and then create another class like SoapServer:
// SoapServer.h
#import "Server.h"
#interface SoapServer : NSObject <Server>
#end
// SoapServer.m
#import “SoapServer.h"
#implementation SoapServer
- (void)callService:(NSString *)service withData:(NSData *)data {
// Code using SOAP
}
#end
Code your main app to just use a pointer to the interface and now you can swap classes without having to change your main code:
// SomeViewController.m
#import “Server.h”
#import “RestServer.h”
#import “SoapServer.h”
…
- (void)someMethod() {
id<Server> myServer;
if ([self shouldIUseSoap])
myServer = [[SoapServer alloc] init];
else
myServer = [[RestServer alloc] init];
[myServer callService:#"loginUser" withData:[self getData]];
}
Now you can change server classes whenever you want and never have to go hunt down all the places in your code where you make calls to callService:withData:. THIS IS THE BENEFIT OF PROGRAMMING TO INTERFACES!
I used Rest vs Soap because I figured people newer to Objective-C might understand that better, but in your case you’d maybe have a ConnectionServer vs SessionServer or something like that.
Another good read on programming to interfaces/protocols can be found here: https://stackoverflow.com/a/384067/504873
If you have to use NSURLCredentialPersistenceForSession if you have to get into a Windows Authentication network...then using NSURLConnection will create multiple problems for you. I'm going through the pain right now and have come to the conclusion that I need both to support iOS 7. Basically, if you use NSURLConnection and willSendRequestForAuthenticationChallenge, you will find that in iOS 7, your session will end with a mind of it's own (seems like a 30 second mind span). So if you have to persist a credential to access more SOAP or whatever, welcome to the terror dome! I will report back to you with code if I find a smooth solution.
At time of writing, NSURLConnection has been deprecated in OS X 10.11 and iOS 9.0 but my Apps need to support OS X 10.7 and iOS 6.
So now you HAVE to use NSURLSession for ongoing projects BUT also support the now deprecated NSURLConnection class for supported legacy OS releases!
I would these days vote for TenaciousJay solution with Compiler warning suppression around the NSURLConnection class implementation.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/* NSURLConnection code here */
#pragma GCC diagnostic pop
The benefit you would you gain by creating two separate classes that do essentially the same thing is that you can eventually CUT off the old, deprecated solution when you can finally drop support for legacy OS releases.
My code decision to use one class or the other would not be based upon some class property but on the result of a Macro like:
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
for iOS or for OS X:
NSString *systemVersion = nil;
if ([[NSProcessInfo processInfo] respondsToSelector:NSSelectorFromString(#"operatingSystemVersion")]) {
NSOperatingSystemVersion operatingSystemVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
systemVersion = [NSString stringWithFormat:#"%ld.%ld.%ld", (long)operatingSystemVersion.majorVersion, (long)operatingSystemVersion.minorVersion, (long)operatingSystemVersion.patchVersion];
} else {
SInt32 versionMajor=0, versionMinor=0, versionPatch=0;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Gestalt(gestaltSystemVersionMajor, &versionMajor);
Gestalt(gestaltSystemVersionMinor, &versionMinor);
Gestalt(gestaltSystemVersionBugFix, &versionPatch);
#pragma GCC diagnostic pop
systemVersion = [NSString stringWithFormat:#"%ld.%ld.%ld", (long)versionMajor, (long)versionMinor, (long)versionPatch];
}
NSLog(#"[Line %d] %s OS X Runtime Version: '%#'", __LINE__, __PRETTY_FUNCTION__, systemVersion);

How do I realize setup() and teardown() before each unit test in the Objective-C Xcode bundle?

I am new to Objective-C and I am trying to start right away with TestDrivenDevelopment, since I find it really assuring, when at least the tests do pass.
Before that I made some Tutorials in Java where I got a little understanding for TDD. Brett Schucherts Video-Tutorials where he goes step by step through coding a full RPNCalculator is a gold mine to learn the stuff by watching him in action.
To reduce code duplication there is for instance this nice thing where you do:
#Before
public void init() {
/* Stuff that which will be set up before the call of each test method/*
}
which is then called before each test you have in your TestClass in Java.
This I want to realize in Objective-C + Xcode. I should mention, that I am using Xcode 4.3 (latest version) and that I am using the built in TestFramework.
The only thing I found in the web that came near what I am looking for was this answer on SO.
Unfortunately I am not able to reproduce the described way of doing things. A minimal runnable example and/or a more detailed explanation for a Newcomer would would be awesome and well appreciated!
By the way, sorry for the bad english. Still learning the language. :-)
Edit:
Here is a minimal example which does not work. Perhaps someone can tell me what is wrong. Xcode seems not to be able to recognize board inside the body of the test methods.
#import <SenTestingKit/SenTestingKit.h>
#interface ABoardShould : SenTestCase
#end
#import "ABoardShould.h"
#implementation ABoardShould
- (void)setUp
{
[super setUp];
int rowCount = 6;
int columnCount = 7;
Board *board = [[Board alloc] initWithShapeRowCount:rowCount andColumnCount:columnCount];
}
- (void)tearDown
{
// Tear-down code here.
[super tearDown];
}
- (void)testHaveItsShapeSetWhenInitialised {
STAssertEquals([board rowCount], rowCount, #"");
STAssertEquals([board columnCount], columnCount, #"");
}
- (void)testHaveTheDimensionsOfItsBoardMatchTheGivenShape {
NSMutableArray *expectedFields = [[NSMutableArray alloc] initWithCapacity:columnCount*rowCount];
for(int i=0; i < (rowCount*columnCount); i++) [expectedFields addObject: [NSNumber numberWithInt: 0]];
STAssertEquals([expectedFields count], [[board fields] count], #"");
}
The setup and teardown methods of your test case class must be called setUp and tearDown. This is described in Xcode Unit Testing Guide: Writing Test Case Methods.
In your example, board is a local variable in the setUp method. You need to make it an instance variable.

Developing a non-GUI user agent in Objective-C using NSDistributedNotificationCenter

I would like to create a user agent in Objective-C that listens for notifications from the default NSDistributedNotificationCenter. The agent will not have a GUI. When I create a Cocoa application (I will also be using Distributed Objects, which I think is only in Cocoa) in Xcode, however, Xcode sets the project as a GUI application.
In the main function, I remove the NSApplicationMain(...) function call to remove the GUI elements from the application. However, now I can't get the thread to wait (listen for) notifications coming in from the NSDistributedNotificationCenter. The app just starts and quits immediately.
I looked into using the NSRunLoop from the current NSThread, however, it seems that NSRunLoops only wait on NSPorts. There's no mention of waiting on NSNotifications.
NSDistributedNotificationCenter is Foundation, so you don't need to create a GUI app. You can create a command line template, for example, and run it from terminal. As a very simple example, you could create an example that just prints out every distributed notification it receives below.
To build, copy into an Xcode template for a Foundation command line app, or simply copy into a text file named something like test_note.m and build according to the comments. In this example, the application will never end (CFRunLoopRun() never returns) and you will have to kill it by hitting CTRL+C from the terminal or killing it with something like kill or the activity monitor.
// test_build.m
// to build: clang -o test_build test_build.m -framework foundation
#import <Foundation/Foundation.h>
#interface Observer : NSObject
- (void)observeNotification:(NSNotification*)note;
#end
#implementation Observer
- (void)observeNotification:(NSNotification*)note
{
NSLog(#"Got Notification: %#", note);
}
#end
int main (int argc, char const *argv[])
{
#autoreleasepool {
Observer* myObserver = [[Observer alloc] init];
[[NSDistributedNotificationCenter defaultCenter] addObserver:myObserver selector:#selector(observeNotification:) name:nil object:nil];
CFRunLoopRun();
}
return 0;
}