5

I have an app that I'm unit testing. Under normal use, the App Delegate sets things up, and starts things running. When I run my unit tests, however, I'd like the App Delegate to not do much, if any of this. How would I go about accomplishing this? It seems that some of that setup stuff is running while the test runner is running, and it tends to throw an exception right around the time a test is run, causing it to fail.

s73v3r
  • 1,751
  • 2
  • 22
  • 48
  • This answer can help [Xcode project how to detect target programatically or how to use env vars] (http://stackoverflow.com/a/6964951/310903) – voromax Jan 20 '14 at 22:20
  • 1
    possible duplicate of [Unit Testing in Xcode, does it run the app?](http://stackoverflow.com/questions/15714697/unit-testing-in-xcode-does-it-run-the-app) You will find the answer there. – Sulthan Jan 20 '14 at 23:39

1 Answers1

1

You want to look into Mocks (or doubles). In general this is a way of diverting you calls when doing testing to bypass things like server calls, printing, logging...

In it's simplest form you can do this by just subclassing the object that you want to modify for your tests.

Say you have

@interface YourClass : NSObject
    @property NSString *dataFromServer;
@end

@implementation YourClass

-(void) load
{
    // Bunch of calls to the server you don't want to do while testing.
    self.dataFromServer = dataFromServerCallsYouDontWantToRun;
}

-(NSString*) getServerData
{
    return dataFromServer;
}

@end

Say you want to test getServerData,but don't want to actually run load because of calls to a database. Say you just want to hard code dataFromServer to be @"Mock".

In your UnitTest Project, inherit from YourClass and override any functions you don't want to actually run in your test.

@interface YourClassMock : YourClass

@end

@implementation YourClassMock

-(void) load
{
    NSLog(@"In Mock");
    self.dataFromServer = @"Mock";
}

@end

Now your test looks like this

- (void) testLoad
{
    YourClassMock yourClass = [[YourClassMock alloc] init];
    [yourClass load];
    STAssertEquals([yourClass getServerData], @"Mock", @"Returns mock data");
}

So you are fully testing getServerData without actually calling your complicated load method.

This is a basic, do it yourself example, but there are a lot of libraries that help speed this along, like OCMock (http://ocmock.org/). This can create mock objects for you without sub classing at all. And you should look into that. But hopefully you understand how you would use this. More info - http://nshipster.com/unit-testing/

ansible
  • 3,569
  • 2
  • 18
  • 29
  • I like your info about mocking, but in the OPs case, how would this work due to race conditions of the app starting vs the testing? I mean, does the XCTestCase get executed at a certain point in the app's startup life that is predictable so that you can mock the app delegate's startup functionality? – stonedauwg Jun 27 '16 at 21:02
  • XCTest is it's own target. It is ran instead of the app to exercise parts of your code. Ideally in unit testing one small part at a time. When you run tests you are not running your app directly. The NSHipster link does a good job explaining it. – ansible Jun 28 '16 at 23:01