More Related Content Similar to iOS Continuous Testing (10) iOS Continuous Testing17. UI Automation is
AWFUL!
• I’ve personally filed over 15 bugs.
• All are still open.
18. UI Automation is
AWFUL!
• I’ve personally filed over 15 bugs.
• All are still open.
• 4.2 broke more than it fixed
19. UI Automation is
AWFUL!
• I’ve personally filed over 15 bugs.
• All are still open.
• 4.2 broke more than it fixed
• Continuing the trend of fail
20. Time spent since August
60
45
30
15
0
Instruments Bug Tracker Blogging HN Reddit RSS Email
29. Step 1
• NSMutableArray *steps = [NSMutableArray array];
30. Step 1
• NSMutableArray *steps = [NSMutableArray array];
[steps addObject:[KIFTestStep stepToTapViewWithAccessibilityLabel:@"Create
Album"]];
31. Step 1
• NSMutableArray *steps = [NSMutableArray array];
[steps addObject:[KIFTestStep stepToTapViewWithAccessibilityLabel:@"Create
Album"]];
[steps addObject:[KIFTestStep
stepToWaitForViewWithAccessibilityLabel:@"createAlbumView"]];
32. Step 1
• NSMutableArray *steps = [NSMutableArray array];
[steps addObject:[KIFTestStep stepToTapViewWithAccessibilityLabel:@"Create
Album"]];
[steps addObject:[KIFTestStep
stepToWaitForViewWithAccessibilityLabel:@"createAlbumView"]];
•
36. Step 3
if (primary) [steps addObject:[KIFTestStep
stepToTapViewWithAccessibilityLabel:@"albumPrimary"]];
37. Step 3
if (primary) [steps addObject:[KIFTestStep
stepToTapViewWithAccessibilityLabel:@"albumPrimary"]];
[steps addObject:[KIFTestStep
stepToTapViewWithAccessibilityLabel:@"createAlbumButton"]];
38. Step 3
if (primary) [steps addObject:[KIFTestStep
stepToTapViewWithAccessibilityLabel:@"albumPrimary"]];
[steps addObject:[KIFTestStep
stepToTapViewWithAccessibilityLabel:@"createAlbumButton"]];
[steps addObject:[KIFTestStep
stepToWaitForAbsenceOfViewWithAccessibilityLabel:@"createAlbumVi
ew"]];
42. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
43. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
44. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
for(Album *a in g.albums){
45. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
for(Album *a in g.albums){
if ([a.name isEqualToString:name]){
46. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
for(Album *a in g.albums){
if ([a.name isEqualToString:name]){
found = YES;
47. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
for(Album *a in g.albums){
if ([a.name isEqualToString:name]){
found = YES;
}
48. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
for(Album *a in g.albums){
if ([a.name isEqualToString:name]){
found = YES;
}
}
49. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
for(Album *a in g.albums){
if ([a.name isEqualToString:name]){
found = YES;
}
}
KIFTestCondition(found, error, [NSString stringWithFormat:@"Failed to create requested
album %@",g.albums]);
50. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
for(Album *a in g.albums){
if ([a.name isEqualToString:name]){
found = YES;
}
}
KIFTestCondition(found, error, [NSString stringWithFormat:@"Failed to create requested
album %@",g.albums]);
return KIFTestStepResultSuccess;
51. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
for(Album *a in g.albums){
if ([a.name isEqualToString:name]){
found = YES;
}
}
KIFTestCondition(found, error, [NSString stringWithFormat:@"Failed to create requested
album %@",g.albums]);
return KIFTestStepResultSuccess;
}]];
52. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
for(Album *a in g.albums){
if ([a.name isEqualToString:name]){
found = YES;
}
}
KIFTestCondition(found, error, [NSString stringWithFormat:@"Failed to create requested
album %@",g.albums]);
return KIFTestStepResultSuccess;
}]];
53. Step 4
[steps addObject:[KIFTestStep stepWithDescription:@"Testing album creation"
executionBlock:^KIFTestStepResult(KIFTestStep *step, NSError *__autoreleasing *error) {
Global *g = [Global shared];
BOOL found = NO;
for(Album *a in g.albums){
if ([a.name isEqualToString:name]){
found = YES;
}
}
KIFTestCondition(found, error, [NSString stringWithFormat:@"Failed to create requested
album %@",g.albums]);
return KIFTestStepResultSuccess;
}]];
•
56. Step 5
#if RUN_KIF_TESTS
[[PhotoWalletTestController sharedInstance]
startTestingWithCompletionBlock:^{
57. Step 5
#if RUN_KIF_TESTS
[[PhotoWalletTestController sharedInstance]
startTestingWithCompletionBlock:^{
exit([[PhotoWalletTestController sharedInstance]
failureCount]);
58. Step 5
#if RUN_KIF_TESTS
[[PhotoWalletTestController sharedInstance]
startTestingWithCompletionBlock:^{
exit([[PhotoWalletTestController sharedInstance]
failureCount]);
}];
59. Step 5
#if RUN_KIF_TESTS
[[PhotoWalletTestController sharedInstance]
startTestingWithCompletionBlock:^{
exit([[PhotoWalletTestController sharedInstance]
failureCount]);
}];
#endif
69. Myth #1: I don’t have time
Variations
• I’m a one-man shop
• My iOS game is not mission-critical
• Testing takes time away from writing new
code
71. Bugs Tests
70
56
42
28
14
0
1.2 1.3 1.4 1.5 1.6 1.7
83. Nobody likes to test
• We need something fun
• We need something easy
• We need something automatic
• We need something obviously beneficial
99. zero-friction testing
• Test by default
• Command-line support w/ work.py
• One-click testing from the bug tracker
• Human tester selected automagically to
code review every patch
106. zero-friction testing
• Errors
• Warnings
• Analyzer results
• Command-U tests
• Merge failures
• KIF UI integration tests
All before a reviewer looks at the patch
108. test once, test forever
• Reviewers only get sane patches
• Once you write a failing test, never
look at the patch again
110. AL
RN LY
TE ON
IN E
USDeployments made easy
Only one person knows
how to do this!
111. AL
RN LY
TE ON
IN E
USDeployments made easy
112. AL
RN LY
TE ON
IN E
USDeployments made easy
113. AL
RN LY
TE ON
IN E
USDeployments made easy
114. AL
RN LY
TE ON
IN E
USDeployments made easy
115. AL
RN LY
TE ON
IN E
USDeployments made easy
116. AL
RN LY
TE ON
IN E
USDeployments made easy
119. buildbot: the bad news
• Large buy-in
• work.py - workflow
• git - version control
• FogBugz - bug tracking
• GitHub - source hosting
123. EN E
OP RC
S OUbuildbot
http://github.com/drewcrawford/buildbot
128. OK, now what?
• Test.
• Test early, test often.
• Test reasonably.
• Test automatically.
129. OK, now what?
• Test.
• Test early, test often.
• Test reasonably.
• Test automatically.
• Think about your workflow
130. • Tiny iOS Developer
• Mix of contracts &
products
• Many other dev tools
like buildbot