Inherits from NSObject
Declared in SLTestController.h

Overview

SLTestController coordinates test execution. Its singleton instance is the primary interface between the application and the tests.

The methods in the SLTestController (DebugSettings) category may be useful in debugging tests.

Tests execute on a background queue. The methods in the SLTestController (AppHooks) category allow tests to access and manipulate application state in a structured, thread-safe manner.

For instance, before running the tests, the application delegate could register a “login manager” singleton as being able to programmatically log a test user in:

 [[SLTestController sharedTestController] registerTarget:[LoginManager sharedManager] 
                                               forAction:@selector(logInWithInfo:)];

When tests need to log in, they could then call loginWithInfo::

[[SLTestController sharedTestController] sendAction:@selector(logInWithInfo:)
                                         withObject:@{
                                                        @"username": @"john@foo.com",
                                                        @"password": @"Hello1234"
                                                     }];

This technique has two main benefits:

  1. It increases the independence of the tests: while one test could (and should) test logging in as a user would, using the UI, the other tests could use the programmatic interface, and not be crippled should the log-in UI break.
  2. It encourages re-use of your application’s code, while not making the tests dependent on your application’s structure: in the example above, the tests need not know which object implements the logInWithInfo: action. And, actions can only return objects that can be copied into the testing context, preventing the application and tests from sharing state.

Target actions may be conditionally defined (and registered) only when integration testing by using the INTEGRATION_TESTING preprocessor macro.

Tasks

Configuring the Default Timeout

Getting the Shared Test Controller

Running Tests

Debugging Tests

Registering and Deregistering App Hooks

Calling App Hooks

  • – sendAction:

    Sends a specified action message to its registered target and returns the result of the message.

  • – sendAction:withObject:

    Sends a specified action message to its registered target with an object as the argument, and returns the result of the message.

Properties

defaultTimeout

Subliminal’s timeout.

@property (nonatomic) NSTimeInterval defaultTimeout

Discussion

Various classes within Subliminal use this timeout to control operations that involve waiting. In particular, this timeout is used to wait for interface elements to become valid and/or tappable, as required by the tests. See [SLUIAElement defaultTimeout].

The default value is 5 seconds.

Declared In

SLTestController.h

shouldWaitToStartTesting

Determines whether the controller should wait, after runTests:withCompletionBlock: is invoked, to start testing.

@property (nonatomic) BOOL shouldWaitToStartTesting

Discussion

If this is YES, the test controller will show an alert after runTests:withCompletionBlock: is invoked and will not begin testing until the developer has dismissed that alert.

This allows the developer time to attach the debugger to the tests. That is done by launching the tests, then clicking the following menu items, in Xcode:

Product -> Attach to Process -> <name of testing target, at top>

This setting will only take effect if the target is built in the “Debug” configuration (with the DEBUG preprocessor macro set). This is to prevent the alert from showing when built (in “Release”) for an unattended, continuous integration run; and to ensure that debug information will be available to the debugger (whereas the Release configuration may optimize that information away).

To build the tests in Debug, click the the “Scheme” dropdown in the upper left-hand corner, then the following menu items:

<Manage Scheme> -> (double-click) <name of your "Integration Tests" scheme> -> 
"Profile" (in the left side-bar)

and change the “Build Configuration” to “Debug”.

Declared In

SLTestController.h

Class Methods

sharedTestController

Returns the test controller.

+ (instancetype)sharedTestController

Return Value

The shared SLTestController instance.

Declared In

SLTestController.h

Instance Methods

deregisterTarget:

Deregisters the target for all actions.

- (void)deregisterTarget:(id)target

Parameters

target

The object to be deregistered.

Discussion

If target is not registered for any actions, this method has no effect.

Declared In

SLTestController+AppHooks.h

deregisterTarget:forAction:

Deregisters the target for the specified actions.

- (void)deregisterTarget:(id)target forAction:(SEL)action

Parameters

target

The object to be deregistered.

action

The action message for which the target should be deregistered.

Discussion

If target is not registered for the specified action, this method has no effect.

Declared In

SLTestController+AppHooks.h

registerTarget:forAction:

Allows application objects to register themselves as being able to perform arbitrary actions.

- (void)registerTarget:(id)target forAction:(SEL)action

Parameters

target

The object to which the action message will be sent.

action

The message which will be sent to the target. It must take either no arguments, or one id-type value conforming to NSCopying. It must return either nothing, or an id-type value conforming to NSCopying.

Discussion

Action messages must take either no arguments, or one id-type value conforming to NSCopying. Messages can return either nothing, or id-type values conforming to NSCopying. (Copying arguments and return values prevents the tests and the application from sharing state.)

Each action is performed on the main thread. The argument (if any) is copied, and the copy passed to the target. The return value (if any) is copied, and the copy passed to the caller.

Only one target may be registered for any given action: if a second target is registered for a given action, the first target will be deregistered for that action. Registering the same target for the same action twice has no effect.

The test controller keeps weak references to targets. It’s still recommended for targets to deregister themselves at appropriate times, though.

Declared In

SLTestController+AppHooks.h

runTests:usingSeed:withCompletionBlock:

Runs the specified tests.

- (void)runTests:(NSSet *)tests usingSeed:(unsigned int)seed withCompletionBlock:(void ( ^ ) ( ))completionBlock

Parameters

tests

The set of tests to run.

seed

The seed to use to randomize the tests. If SLTestControllerRandomSeed is passed, the test controller will choose a seed.

completionBlock

An optional block to execute once testing has finished.

Discussion

Tests are run on a background queue. Tests run in ascending order of group, and then within each group, in an order randomized using the specified seed. Clients should generally pass SLTestControllerRandomSeed to let the test controller choose a seed. If any tests fail, the test controller will log the seed that was used, so that the run order may be reproduced by invoking this method with that seed.

Tests must support the current platform in order to be run. If any tests are focused, only those tests will be run.

When using a given seed, tests execute in the same relative order regardless of focus. That is, if a set of tests | A, B, C, D | (all unfocused) are run in order [ B, A, C, D ] when using a certain seed, when tests B and C are focused, they will be run in order [ B, C ].

When all tests have finished, the completion block (if provided) will be executed on the main queue. The test controller will then signal UIAutomation to finish executing commands.

Declared In

SLTestController.h

runTests:withCompletionBlock:

Run the specified tests by invoking runTests:usingSeed:withCompletionBlock: with SLTestControllerRandomSeed and the specified completion block.

- (void)runTests:(NSSet *)tests withCompletionBlock:(void ( ^ ) ( ))completionBlock

Parameters

tests

The set of tests to run.

completionBlock

An optional block to execute once testing has finished.

Declared In

SLTestController.h

sendAction:

Sends a specified action message to its registered target and returns the result of the message.

- (id)sendAction:(SEL)action

Parameters

action

The message to be performed.

Return Value

The result of the action, if any; otherwise nil.

Discussion

This method must not be called from the main thread (it is intended to be called by tests).

The message will be performed on the main thread. The returned value (if any) will be copied, and the copy passed to the caller.

Exceptions

SLAppActionTargetDoesNotExistException

Thrown if, after several seconds' wait, no target has been registered for action, or a registered target has fallen out of scope.

Declared In

SLTestController+AppHooks.h

sendAction:withObject:

Sends a specified action message to its registered target with an object as the argument, and returns the result of the message.

- (id)sendAction:(SEL)action withObject:(id<NSCopying>)object

Parameters

action

The message to be performed.

object

An object which is the sole argument of the action message.

Return Value

The result of the action, if any; otherwise nil.

Discussion

This method must not be called from the main thread (it is intended to be called by tests).

The message will be performed on the main thread. The argument will be copied, and the copy passed to the target. The returned value (if any) will be copied, and the copy passed to the calling SLTest.

Exceptions

SLAppActionTargetDoesNotExistException

Thrown if, after several seconds' wait, no target has been registered for action, or a registered target has fallen out of scope.

Declared In

SLTestController+AppHooks.h