Running Parameterized Tests in iOS

- ppilone - iOS Development

One major disadvantage to [SenTestingKit|XCTestKit] is the inability to run the same test with different sets of parameters. Helper methods are an option, but you still wind up with a test case littered with (almost) duplicate test methods. Recently I borrowed a solution from the world of Cucumber testing and wrote PTKTestKit, which supports writing a single test method that will execute once for each set of parameters.

PTKTestCase

Most of the magic happens in the PTKTestCase class, a subclass of SenTestCase. At the surface it functions just like SenTestCase, but with additional support for running outline tests. When you want to test some new functionality, start by creating a subclass of PTKTestCase.

Outline Tests

Outline tests are structured just like SenTestCase test methods, with the caveat of having to be prefixed with ‘outlineTest’. Below is an example of an outline test that taps a row in a table view and waits for a specific view to appear:

1
2
3
4
5
6
- (void)outlineTestForViewingDetail
{
    NSLog(@"INFORMATION: Example: %@", self.example[@"name"]);
    [tester tapViewWithAccessibilityLabel:self.example[@"name"] traits:UIAccessibilityTraitStaticText];
    [tester waitForViewWithAccessibilityLabel:self.example[@"value"] traits:UIAccessibilityTraitStaticText];
}

The outline test retrieves its test values from the ‘example’, which is an instance of PTKOutlineExample. An example holds the values for a single run of an outline test. Outline examples are vended by your PTKTestCase subclass by overriding

1
+ (NSArray *)examplesForOutlineTestWithSelector:(SEL)selector;

There are two ways you can create outline examples: either inline (by alloc+init’ing a PTKOutlineExample instance) or providing a resource file to the PTKOutlineExample class. At the time of writing this, PTKOutlineExample expects the resource file to contain a JSON array of hashes. It’s important to note that PTKOutlineExamples require a name: so if you’re providing a resource file there must be a ‘name’ key/value pair in each hash.

Xcode 5 Test Navigator

In addition to running an outline test once for each example, PTKTestKit dynamically generates test names based on the outline test selector and outline example name. This ensures that each run of the outline test can be seen in Xcode 5′s test navigator.

Example

The sample PTKTestCase demonstrates how you can provide outline examples for a specific outline test and mix in standard test methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#import "PTKTestCase.h"

 
@interface PTKDetailTests : PTKTestCase
@end

#import "PTKDetailTests.h"
 

#import <KIF/KIF.h>

@implementation PTKDetailTests
 
+ (NSArray *)examplesForOutlineTestWithSelector:(SEL)selector
{
    return [PTKOutlineExample outlineExamplesFromResource:@"sample-data" bundle:nil error:nil];
}
 
- (void)outlineTestForViewingDetail
{
    NSLog(@"INFORMATION: Example: @", self.example[@"name"]);
    [tester tapViewWithAccessibilityLabel:self.example[@"name"] traits:UIAccessibilityTraitStaticText];
    [tester waitForViewWithAccessibilityLabel:self.example[@"value"] traits:UIAccessibilityTraitStaticText];
}
 
- (void)testStaticRow
{
    [tester tapViewWithAccessibilityLabel:@"Test Static Row" traits:UIAccessibilityTraitStaticText];
    [tester waitForViewWithAccessibilityLabel:@"Static Row" traits:UIAccessibilityTraitStaticText];
}
 
@end

In this sample I load test examples from a resource file named “sample-data” — you can check the `selector` argument in order to return different examples for multiple outline tests. The `outlineTestForViewingDetail` uses its test case’s example to populate the accessibility label parameters. At its core, PTKOutlineExample is a key/value store; so feel free to have as many parameters as you need for a test. This test case will run the outline test twice and the `testStaticRow` method once.

The resource file used in this example:

1
2
3
4
5
6
7
8
9
10
[
 {
    "name" : "Test Foo",
    "value" : "Foo"
 },
 {
    "name" : "Test Bar",
    "value" : "Bar"
 }
]

And the output after running the tests in Xcode 5:

PTKTestKit Test Output

Get The Code

Jump on over to the PTKTestKit project on Github to get the code. There is also a more detailed example and instructions on how to install it in the README.