Run logic tests in Xcode 4 without launching the simulator

被刻印的时光 ゝ 提交于 2019-11-28 18:15:56

Please can someone tell me how to have the test harness not instantiate the whole app? My app is event driven, and it sends a bunch of events through when it starts up that mess with my tests.

I use Xcode 4's built-in testing. App instantiation may seem like a pain, but as I write on Xcode Unit Testing: The Good, the Bad, the Ugly, it makes it possible to write tests without distinguishing between logic tests and application tests. Specifically, it lets me write unit tests for view controllers.

Here's what I do to avoid my full startup sequence:

Edit the scheme

  • Select the Test action
  • In "Test" select the Arguments tab
  • Disable "Use the Run action's options"
  • Add an environment variable, setting runningTests to YES

Edit your app delegate

  • Add the following to -application:didFinishLaunchingWithOptions: as soon as it makes sense to:

    #if DEBUG
        if (getenv("runningTests"))
            return YES;
    #endif
    
  • Do the same for -applicationDidBecomeActive: but simply return.

Update: I have changed my approach. See How to Easily Switch Your App Delegate for Testing.

In the last xcode version (5.0.2) you can do this in very easy way. Choose your Test target, "General" tab. Set "None" in field "Target". Then tap on "Build phases" tab and remove your Main target from "Target dependencies".

In your situation, I am assuming that you have a separate Logic Tests and Application Tests target (if not - you need to). In your schemes configuration you define which targets are built for the 'Test' scheme. If your application tests are not running, the simulator will not launch.

I suspect that you might be trying to run 'logic tests' in an 'Application tests' target (such as the one created by default by Xcode). See more about this difference here (and how to set ut up).

Praveen Kumar

It was pointed out in an earlier answer that logic tests are the right thing to do for this scenario. I had very tough time in getting the logic tests working with XCode Version 4.3.2 (4E2002). Looking at Apple's sample unit test project helped me to understand how to do this with a clear separation. In that example, logic tests test files from the library target, not the application target. The model was encapsulated into a library which was then linked with the main target and logic tests target. The application target contained only views and controllers.

Based on this model, this is what I did to get my logic tests work correctly. Create a new target (Cocoa Touch Static Library) and move all files to be logic tested (typically all your models) to this new target. Under "Build Phases" settings add this new library in "Link Binary With Libraries" of your application target and logic tests target.

I can imagine that these instructions are little confusing. If you dissect the sample project that is mentioned above you will get a better idea.

mxcl

Note, untested on Xcode 5.

I used @jon-reid’s answer, but found that Xcode adds environment-variables to the xcuserstated part of XcodeProjects, and these are user specific and not typically committed to the repository. Thus I swizzle my AppDelegate to override its loading:

@implementation MyAppDelegate (Testing)

+ (void)initialize {
    SEL new = @selector(application:didFinishLaunchingWithOptions:);
    SEL orig = @selector(swizzled_application:didFinishLaunchingWithOptions:);
    Class c = [self class];
    Method origMethod = class_getInstanceMethod(c, orig);
    Method newMethod = class_getInstanceMethod(c, new);

    if (class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
        class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    } else {
        method_exchangeImplementations(origMethod, newMethod);
    }
}

- (BOOL)swizzled_application:(id)app didFinishLaunchingWithOptions:(id)opts {
    return YES;
}

@end

Note, that the following is simpler and still works, though I'm not sure it is reliable:

@implementation MyAppDelegate (Testing)

- (BOOL)application:(id)app didFinishLaunchingWithOptions:(id)opts {
    return YES;
}

@end

This works because categories of methods in dynamically loaded components (like the testing bundle) take precedence. Swizzling feels safer though.

Using xCode 7 and xctool

xctool is capable of executing unit tests without the simulator.

To get this working,

1 . Update the target settings 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
justin

i've used GHUnit to create osx/ios compatible test suites. there are a few issues, but i found it was more reliable/compatible/straightforward than OCUnit.

GHUnit provides basic template projects for OS X and iOS, which makes initial setup simple.

Note: I generally just use my own kit for most of my testing.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!