I want to run tests in Xcode 4 using OCUnit without launching the simulator. Please, don't try and convince me I am doing unit testing wrong or anything like that. I like to do TDD the traditional way: write the API for the class in the tests, then make the class pass the tests. I will write separate tests that are end-to-end that run in the simulator.
If there's no way to do this, then 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.
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
toYES
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 simplyreturn
.
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).
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.
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
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.
来源:https://stackoverflow.com/questions/7274711/run-logic-tests-in-xcode-4-without-launching-the-simulator