How to determine whether code is running during a unit test run - iphone

I need to have some kind of if statement to ignore certain bits of code e.g. pop dialog if the coding is being run as part of a unit test.
Does anyone have any idea have to do this - similar to debug?

I prefer runtime solution, not a one based on preprocessor:
int main(int argc, char* argv[]) {
#autoreleasepool {
BOOL tests = NO;
for (int i = 0; i < argc; i++) {
NSString* argument = [NSString stringWithCString:argv[i] encoding:NSASCIIStringEncoding];
if ([argument isEqualToString:#"-SenTest"]) {
tests = YES;
break;
}
}
if (tests) {
//save YES to a global variable and use it whenewer you want
}
UIApplicationMain(...)
}
}
I am actually using this to have a different UIApplicationDelegate when unit tests are run, so no UI code (DB opening, notifications started etc) collides with my test cases.

Related

Unit Testing in Xcode, does it run the app?

I'm running into a strange problem that I haven't run into before.
When you do cmd+U to run your Unit Tests (OCUnit for example) does it actually call the main.m, new up the appDelegate and run the app as if your had pressed cmd+R?
I only ask because I'm using CoreData behind this DataLayer. I'm mocking out the DataLayer successfully in my tests, but once I implemented a getAll method that is actually calling CoreData, the app/xcode is throwing an exception about the managed object model can't be nil. Which I understand, but I'm not meaning to actually new up the DataLayer class, and I've put a break point in my mainviewcontroller loadView method where it is calling the DataLayer getAll method. It shouldn't matter with tests because this is a mock object, but it's apparently calling the real instance.
So back to my question, when pressing cmd+U does it also run the app first then run the tests?
The application is actually run but there is a trick you can use to prevent it from running.
int main(int argc, char* argv[]) {
int returnValue;
#autoreleasepool {
BOOL inTests = (NSClassFromString(#"SenTestCase") != nil
|| NSClassFromString(#"XCTest") != nil);
if (inTests) {
//use a special empty delegate when we are inside the tests
returnValue = UIApplicationMain(argc, argv, nil, #"TestsAppDelegate");
}
else {
//use the normal delegate
returnValue = UIApplicationMain(argc, argv, nil, #"AppDelegate");
}
}
return returnValue;
}
Here's a variation of Sulthan's answer that uses XCTest, which is the default for test classes generated by XCode 5.
int main(int argc, char * argv[])
{
#autoreleasepool {
BOOL runningTests = NSClassFromString(#"XCTestCase") != nil;
if(!runningTests)
{
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
else
{
return UIApplicationMain(argc, argv, nil, #"TestAppDelegate");
}
}
}
This goes into main.m, which should be under Supporting Files in a standard project layout.
Then in your tests directory add:
TestAppDelegate.h
#import <Foundation/Foundation.h>
#interface TestAppDelegate : NSObject<UIApplicationDelegate>
#end
TestAppDelegate.m
#import "TestAppDelegate.h"
#implementation TestAppDelegate
#end
In Swift, I prefere to bypass a normal execution path inside application: didFinishLaunchingWithOptions:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
guard normalExecutionPath() else {
window = nil
return false
}
// regular setup
return true
}
private func normalExecutionPath() -> Bool {
return NSClassFromString("XCTestCase") == nil
}
Code inside guard will remove any views created from storyboard.
If you're using Swift (you probably don't have a main.c), you have to do these steps :
1: remove #UIApplicationMain in AppDelegate.swift
2: Create an empty TestingAppDelegate.swift
import UIKit
class TestingAppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
}
3: Create a file called main.swift :
import Foundation
import UIKit
let isRunningTests = NSClassFromString("XCTestCase") != nil
if isRunningTests {
UIApplicationMain(C_ARGC, C_ARGV, nil, NSStringFromClass(TestingAppDelegate))
} else {
UIApplicationMain(C_ARGC, C_ARGV, nil, NSStringFromClass(AppDelegate))
}
I found another solution to the problem:
int main(int argc, char * argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, ({
![NSProcessInfo processInfo].environment[#"XCTestConfigurationFilePath"] ?
#"AppDelegate" :
nil;
}));
}
}
From here: http://qualitycoding.org/app-delegate-for-tests/#comment-63984
Using xCode 7 and xCtool
xctool is capable of executing unit tests without running the app.
To get this working,
1 . Update target settings to run without a host app.
Select your project --> then test target --> Set the host application to none.
2. Install xctool , if you don't have it.
brew install xctool
3. Run the tests using terminal with xctool.
xctool -workspace yourWorkspace.xcworkspace -scheme yourScheme run-tests -sdk iphonesimulator
You can do that by setting the Host Application to None in your Tests Target.
Yes, your test target will have a target dependency to the app target, so the app target will be built when you press Cmd+U or Cmd+Shift+U.
Excellent answers above that suggest dynamically changing the application delegate at run time.
The small modification I make is to detect a unit test run by querying NSProcessInfo. The advantage is that you don't need to have a class that can be detected to see if unit tests are running.
int main(int argc, char * argv[])
{
// Put your App delegate class here.
const Class appDelegateClass = [ATAppDelegate class];
NSDictionary *const environmentDictionary =
[[NSProcessInfo processInfo] environment];
const BOOL runningUnitTests =
environmentDictionary[#"XCInjectBundleInto"] != nil;
NSString *delegateName =
runningUnitTests ? nil : NSStringFromClass(appDelegateClass);
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, delegateName);
}
}
The #"XCInjectBundleInto" property in environmentDictionary is the path to your unit tests bundle and is set up by Xcode.
I use the approach of Tomasz Bak plus some code of dwb answer and come up with the following:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL runningTests = NSClassFromString(#"XCTestCase") != nil;
if (runningTests) {
self.window.rootViewController = [UIViewController new];
return true;
}
// Your normal code below this
....
}

Objective C Seg Fault that only occurs when compiler optimizations are enabled

I'm stumped trying to debug an issue on iOS that seems to only occur with Release builds which seems to implicate that the optimizer is doing something that isn't playing nicely with my code. The code that crashes is some code that is serializing some binary data into a NSMutableData instance as follows.
[_data increaseLengthBy:sizeof(CFSwappedFloat64)];
*((CFSwappedFloat64 *)[self pointerAtOffset]) = CFConvertFloat64HostToSwapped(value);
_offset += sizeof(CFSwappedFloat64);
_data is a NSMutableData instance. pointerAtOffset and the init method for this class is defined as follows.
- (unsigned char *)pointerAtOffset {
return ((unsigned char *)_data.mutableBytes) + _offset;
}
- (id)init {
if( self = [super init] ) {
_data = [[NSMutableData alloc] initWithCapacity:1028];
_offset = 0;
}
return self;
}
Now the strange thing is that if I add a NSLog print statement, it fixes the bug.
[_data increaseLengthBy:sizeof(CFSwappedFloat64)];
NSLog(#"%d - %d", (int)_data.mutableBytes, _offset);
*((CFSwappedFloat64 *)[self pointerAtOffset]) = CFConvertFloat64HostToSwapped(value);
_offset += sizeof(CFSwappedFloat64);
Any ideas what might be causing this? It's kind of unnerving to deploy code that works because of a NSLog statement.
This reminds me of the armv6 Thumb instruction problems. If you change your debug build settings to optimize to Fastest,Smallest and it crashes, then that is your problem.

Implementing the PT_DENY_ATTACH anti-piracy code

I've been tryign to implement the following anti piracy code from this wiki:
http://theiphonewiki.com/wiki/index.php?title=Bugging_Debuggers
But despite following it to the letter my app exits with a
Program exited with status value:45.
When i test it. If i comment out the function call disable_gdb(); the app runs as normal.
What is it that I'm doing wrong. Or is it that the code is doing as it should.. and exits while xcode is attached?
#import <UIKit/UIKit.h>
#import <dlfcn.h>
#import <sys/types.h>
typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif // !defined(PT_DENY_ATTACH)
int main(int argc, char *argv[])
{
NSLog(#"Main Called ");
disable_gdb();
NSLog(#"After cracker code");
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
void disable_gdb()
{
void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace");
ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
dlclose(handle);
}
int main3(int argc, char *argv[])
{
return -1;
}
Kindest Regards,
-Code
The code is functioning as intended. That said, I should tell you that you're wasting your time. This approach will only work if gdb and the attacker/programmer are cooperative. The whole point of tools like gdb is that they are extremely versatile and if a simple "bug" like this stopped them dead in their tracks, someone would fix it very quickly. :)
As described on this page, you can just do the following from within gdb:
(gdb) break ptrace
commands 1
return
continue
end

How to catch sigpipe in iphone app?

How can i catch sigpipe in iphone/objective-c?
thanks
One important fact for testing the SigPipeHandler:
For me it did not work when the debugger was atached. So when running an app directly from XCode the Handler is not called.
Meanwhile, on a device without the debugger attached the handler works as expected.
Use old good POSIX code:
#include <signal.h>
void SigPipeHandler(int s);
void SigPipeHandler(int s)
{
// do your handling
}
Init in some place (main.m?) with
signal(SIGPIPE, SigPipeHandler);
Try setting SO_NOSIGPIPE as documented here:
How to prevent SIGPIPEs (or handle them properly)
The first answer doesn't work.
Also I'm trying to use solution described in reference of second post:
int main(int argc, char *argv[ ]) {
struct sigaction mySigAction;
mySigAction.sa_handler = SIG_IGN;
sigemptyset(&mySigAction.sa_mask);
sigaction(SIGPIPE, &mySigAction, NULL);
...
}
but this code doesn't work too. Anybody know solution of this problem?
The first answer works fine. but you should put every thing in the main.mm file.
And in static class(Singleton) , it also works.
#import <UIKit/UIKit.h>
#import <sys/signal.h>
#if TARGET_IPHONE_SIMULATOR
#endif
void SigPipeHandler(int s)
{
NSLog(#"We Got a Pipe Single :%d____________",s);
}
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
signal(SIGPIPE, SigPipeHandler);
int retVal = UIApplicationMain(argc, argv, nil, #"FullAppDelegate");
[pool release];
return retVal;
}

Any way to tell if my iPhone app is running under the debugger at runtime?

I would like to have my error handling code behave differently if it is running under the debugger. Specifically, if I am running on a handset, not attached to a debugger and fail an assertion I want to send the error to my server. When I am under gdb, I want to break into the debugger.
Although I can imagine how Apple would write the code, I can't find any documentation of a runtime way to test for the presence of the debugger.
The method described here worked fine for me
I tested by placing it in -(void)viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
int mib[4];
size_t bufSize = 0;
int local_error = 0;
struct kinfo_proc kp;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
bufSize = sizeof (kp);
if ((local_error = sysctl(mib, 4, &kp, &bufSize, NULL, 0)) < 0) {
label.text = #"Failure calling sysctl";
return;
}
if (kp.kp_proc.p_flag & P_TRACED)
label.text = #"I am traced";
else
label.text = #"I am not traced";
}
Why not redefine assert to do what you want, when not compiled for debug?
Another option, is to create your own assert function, where you can then add a breakpoint on loading into GDB.
The assert prototype is
void assert(int expression);
void assert(int expression)
{
if( !expression )
{
// enable break point here
// log to server
}
}
or add the break point into the log to server code.