XCode7 UITesting - how to add main target classes

2019-09-11 04:03发布

问题:

I'm doing UI testing with XCode7 and need a way to reset my app to some initial state. I have a method to do so in one of my .m files that are part of the main target.

How can I make classes from the main target to be available from within a UITestCase?

I tried regular import, but get a linker error:

#import <XCTest/XCTest.h>
#import "CertificateManager.h"

@interface UITests : XCTestCase

@end

-(void)testWelcomeScreen
{
//put the app into initial state
    [[CertificateManager sharedInstance] resetApplication];
//... proceed with test
}

Error:

Undefined symbols for architecture i386:
  "_OBJC_CLASS_$_CertificateManager", referenced from:
      objc-class-ref in UITests.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I have compared this to the Unit test target, but cant see differences beyond that the unit test target has "Allow testing host application APIs" checked, while UITest target does not have this option at all.

回答1:

UI Tests run in a separate process from your production app. This means that you cannot access any production classes from your test suite.

The only interaction UI Tests have, outside of touching the screen, is by setting launch arguments or modifying the launch environment.

You can use either of these to reset your app when it launches. For example, in your UI Testing tests:

@interface UITests : XCTestCase
@property (nonatomic) XCUIApplication *app;
@end

@implementation FooUITests

- (void)setUp {
    [super setUp];

    self.app = [[XCUIApplication alloc] init];
    self.app.launchArguments = @[ @"UI-TESTING" ];
    [self.app launch];
}

- (void)testExample {
    // ... //
}

@end

Then, when your app launches you can check for this argument. If it exists, call your app's "reset" method.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    if ([[[NSProcessInfo processInfo] arguments] containsObject:@"UI-TESTING"]) {
        [[CertificateManager sharedInstance] resetApplication];
    }

    return YES;
}