Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cocoaheads Montréal : Automated testing for iOS

Cocoaheads Montréal : Automated testing for iOS

Cocoaheads Montréal - 11/02/2014

Romain Pouclet

February 12, 2014
Tweet

More Decks by Romain Pouclet

Other Decks in Programming

Transcript

  1. Reasons to test ▸ Make sure everything work as expected

    ▸ Avoid regression ▸ Natural documentation ▸ Ease maintenance and refactoring ▸ Sleep better at night
  2. Reasons not to test Prototyping Deadlines Testing is hard I

    don't need them, I know what I'm doing
  3. Reasons not to test Prototyping Deadlines Testing is hard I

    don't need them, I know what I'm doing
  4. Reasons not to test Prototyping Deadlines Testing is hard I

    don't need them, I know what I'm doing
  5. Reasons not to test Prototyping Deadlines Testing is hard I

    don't need them, I know what I'm doing
  6. Example : XML parsing ▸ Augmented reality application using Vuforia

    ▸ Metadata stored here (Vuforia) and there (Client database)
  7. Example : XML parsing <?xml version="1.0" encoding="utf-8" ?> <book> <book_id>1</book_id>

    <title>Harry Potter and the goblet of fire</title> <!-- Other nodes --> <recommandations> <book> <book_id>2</book_id> <title>Harry Potter and the Deathly Hallows</title> </book> <!-- MORE BOOKS --> </recommandations> </book>
  8. Dead simple XML parsing PCSGetBookDetailsParserDelegate *parsingDelegate = [[PCSGetBookDetailsParserDelegate alloc] init];

    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL: url]; parser.delegate = parsingDelegate; BOOL result = [parser parse]; PCSBook *book = parsingDelegate.book;
  9. "There are too much metadata on Vuforia, please only use

    item and image data and fetch the rest from the backoffice"
  10. There is a bug in the application when the user

    search for a book on a tuesday — A (nice) client
  11. Write a failing test case - (void)testItemIdIsNotOverridenByRecommandationItemId { NSURL *url

    = [[NSBundle bundleForClass: [self class]] URLForResource: @"342279" withExtension: @"xml"]; NSAssert(url, @"URL for sample payload should be properly loadded"); PCSGetBookDetailsParserDelegate *parsingDelegate = [[PCSGetBookDetailsParserDelegate alloc] initWithWhiteList: @[@"imagedata", @"item"]]; NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL: url]; parser.delegate = parsingDelegate; BOOL result = [parser parse]; NSAssert(result, @"Payload shoud be successfully parsed."); PCSBook *book = parsingDelegate.book; XCTAssertEqualObjects(@"342279", book.item); }
  12. Failing test case : load data you know NSURL *url

    = [[NSBundle bundleForClass: [self class]] URLForResource: @"342279" withExtension: @"xml"]; NSAssert(url, @"URL for sample payload should be properly loadded");
  13. Failing test case : do the actual parsing PCSGetBookDetailsParserDelegate *parsingDelegate

    = [[PCSGetBookDetailsParserDelegate alloc] initWithWhiteList: @[@"imagedata", @"item"]]; NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL: url]; parser.delegate = parsingDelegate; BOOL result = [parser parse]; NSAssert(result, @"Payload shoud be successfully parsed.");
  14. Failing test case : add your assertions PCSBook *book =

    parsingDelegate.book; XCTAssertEqualObjects(@"342279", book.item);
  15. Or... Xctool (facebook) $ brew install xctool $ xctool -project

    XMLParsing.xcodeproj -scheme XMLParsing test
  16. The secret of happiness* 1. Find a bug 2. Write

    a (failing) test case 3. Fix the bug 4. Repeat (* not really)
  17. Easy to read - (void)testSomethingShouldHappenThisWay { Stuff *someStuff = [[Stuff

    alloc] init]; XCTAssertEqualObjects(@"Expected result", [someStuff performSomeAction], @"The action should do something") }
  18. Avoid singletons @implementation PCSSuperImportantObject - (instancetype)init { self = [super

    init]; if (self) { self.connection = [PCSTwitterConnection sharedConnection]; } return self; } @end
  19. ... So you can mock them later id connection =

    [OCMockObject mockForClass: [PCSTwitterConnection class]]; [[[connection stub] andReturn: @367] followerCountsForUsername: [OCMArg any]]; NSLog(@"Followers = %@", [connection followerCountsForUsername: @"CocoaheadsMTL"]);
  20. Don't test everything HSWizard *harry = [[HSWizard alloc] init]; harry.house

    = @"Gryffindor"; XCTAssertEqualsObject(@"Gryffindor", harry.house);
  21. Acceptance testing using KIF - (void)testSuccessfulLogin { [tester enterText: @"https://confluence-url.com"

    intoViewWithAccessibilityLabel: @"Confluence URL"]; [tester enterText: @"apple.review" intoViewWithAccessibilityLabel: @"Confluence username"]; [tester enterText: @"applereview" intoViewWithAccessibilityLabel: @"Confluence password"]; [tester tapViewWithAccessibilityLabel: @"Log In"]; // Verify that the login succeeded [tester waitForTappableViewWithAccessibilityLabel: @"Spaces list"]; [tester tapRowInTableViewWithAccessibilityLabel: @"Spaces list" atIndexPath: [NSIndexPath indexPathForRow: 0 inSection: 0]]; [tester waitForTappableViewWithAccessibilityLabel: @"Main menu"]; }
  22. Acceptance testing using Frank Feature: As a user I want

    to be able to see the weather of a region So I can see if I need to bring flip flops or a snow shovel Scenario: I need to be able to select a city Given I launch the app And I touch "Select weather city" And I wait to see "Alma" And I touch "Alma" Then I should see "Alma" $ cucumber features/weather.feature
  23. It is not about testing everything It is about raising

    your level of confidence in your code