Unit testing with Kiwi - CocoaConf San Jose 2013

Unit testing with Kiwi - CocoaConf San Jose 2013

Find out why unit testing will make your developer life easier and how to get started testing your own app using Kiwi, a popular open-source unit testing library. We look at how to get setup with Kiwi. Then we learn the fundamentals of testing, along with some common patterns and idioms.

Fe6b81005d1553accd6b2a28f6a2bef1?s=128

Pete Hodgson

April 18, 2013
Tweet

Transcript

  1. Unit testing with Kiwi CocoaConf San Jose 2013 Thursday, April

    18, 13
  2. me me me Pete Hodgson Consultant at ThoughtWorks @ph1 blog.thepete.net

    Thursday, April 18, 13
  3. Shameless Plug http://iphreaksshow.com Thursday, April 18, 13

  4. Unit Testing why should you care? Thursday, April 18, 13

  5. Thursday, April 18, 13

  6. Thursday, April 18, 13

  7. Thursday, April 18, 13

  8. Thursday, April 18, 13

  9. Thursday, April 18, 13

  10. 1. write code 2. submit stack of cards 3. wait

    (probably overnight) 4. find out if your program worked Thursday, April 18, 13
  11. Feedback Thursday, April 18, 13

  12. write it check it Thursday, April 18, 13

  13. feedback Thursday, April 18, 13

  14. punchcards 24 hrs Thursday, April 18, 13

  15. big ol’ C++ program 60 mins Thursday, April 18, 13

  16. http://xkcd.com/303/ Thursday, April 18, 13

  17. an iOS app 1o secs Thursday, April 18, 13

  18. what’s next? Thursday, April 18, 13

  19. of feedback Speed Thursday, April 18, 13

  20. of feedback Quality Thursday, April 18, 13

  21. syntax vs. semantics Thursday, April 18, 13

  22. does it compile? static analysis unit testing Thursday, April 18,

    13
  23. does it compile? static analysis unit testing Thursday, April 18,

    13
  24. unit testing means better feedback Thursday, April 18, 13

  25. Unit Testing Thursday, April 18, 13

  26. what’s a unit test? Thursday, April 18, 13

  27. x+1 12 13 Thursday, April 18, 13

  28. system under test in out Thursday, April 18, 13

  29. “my first unit test” with kiwi Thursday, April 18, 13

  30. what is kiwi? open-source tool builds on top of SenTest

    adds nicer ways of organizing tests adds nicer ways to make assertions adds ability to mock/stub Thursday, April 18, 13
  31. #import "Kiwi.h" SPEC_BEGIN(MyFirstSpec) describe(@"Basic Arithmetic", ^{ it(@"can increment 12",^{ [[theValue(12+1)

    should] equal:theValue(13)]; }); }); SPEC_END myFirstSpec.m Thursday, April 18, 13
  32. #import "Kiwi.h" SPEC_BEGIN(MyFirstSpec) describe(@"Basic Arithmetic", ^{ it(@"can increment 12",^{ [[theValue(12+1)

    should] equal:theValue(13)]; }); }); SPEC_END myFirstSpec.m Thursday, April 18, 13
  33. #import "Kiwi.h" SPEC_BEGIN(MyFirstSpec) describe(@"Basic Arithmetic", ^{ it(@"can increment 12",^{ [[theValue(12+1)

    should] equal:theValue(13)]; }); }); SPEC_END myFirstSpec.m Thursday, April 18, 13
  34. #import "Kiwi.h" SPEC_BEGIN(MyFirstSpec) describe(@"Basic Arithmetic", ^{ it(@"can increment 12",^{ [[theValue(12+1)

    should] equal:theValue(13)]; }); }); SPEC_END Thursday, April 18, 13
  35. #import "Kiwi.h" SPEC_BEGIN(MyFirstSpec) describe(@"Basic Arithmetic", ^{ it(@"can increment 12",^{ [[theValue(12+1)

    should] equal:theValue(13)]; }); }); SPEC_END Thursday, April 18, 13
  36. Setting up your project with Kiwi Thursday, April 18, 13

  37. Guide: Up and Running with Kiwi (on Kiwi’s github wiki)

    Thursday, April 18, 13
  38. or, just use cocoapods Thursday, April 18, 13

  39. my first real test loading stations Thursday, April 18, 13

  40. in out system under test Thursday, April 18, 13

  41. [ { “name”:”foo”, ... }, {...} ] Station Station loadStations

    Thursday, April 18, 13
  42. describe(@"Station", ^{ it(@"loads from JSON correctly",^{ NSArray *rawStations = @[

    @{@"abbr":@"s1",@"name":@"station one"}, @{@"abbr":@"s2",@"name":@"station two"}, ]; NSArray *stations = [Station loadStations:rawStations]; [[theValue(stations.count) should] equal:theValue(2)]; [[[stations[0] abbr] should] equal:@"s1"]; [[[stations[0] name] should] equal:@"station one"]; [[[stations[1] abbr] should] equal:@"s2"]; [[[stations[1] name] should] equal:@"station two"]; }); }); Thursday, April 18, 13
  43. describe(@"Station", ^{ it(@"loads from JSON correctly",^{ NSArray *rawStations = @[

    @{@"abbr":@"s1",@"name":@"station one"}, @{@"abbr":@"s2",@"name":@"station two"}, ]; NSArray *stations = [Station loadStations:rawStations]; [[theValue(stations.count) should] equal:theValue(2)]; [[[stations[0] abbr] should] equal:@"s1"]; [[[stations[0] name] should] equal:@"station one"]; [[[stations[1] abbr] should] equal:@"s2"]; [[[stations[1] name] should] equal:@"station two"]; }); }); Thursday, April 18, 13
  44. describe(@"Station", ^{ it(@"loads from JSON correctly",^{ NSArray *rawStations = @[

    @{@"abbr":@"s1",@"name":@"station one"}, @{@"abbr":@"s2",@"name":@"station two"}, ]; NSArray *stations = [Station loadStations:rawStations]; [[theValue(stations.count) should] equal:theValue(2)]; [[[stations[0] abbr] should] equal:@"s1"]; [[[stations[0] name] should] equal:@"station one"]; [[[stations[1] abbr] should] equal:@"s2"]; [[[stations[1] name] should] equal:@"station two"]; }); }); Thursday, April 18, 13
  45. describe(@"Station", ^{ it(@"loads from JSON correctly",^{ NSArray *rawStations = @[

    @{@"abbr":@"s1",@"name":@"station one"}, @{@"abbr":@"s2",@"name":@"station two"}, ]; NSArray *stations = [Station loadStations:rawStations]; [[theValue(stations.count) should] equal:theValue(2)]; [[[stations[0] abbr] should] equal:@"s1"]; [[[stations[0] name] should] equal:@"station one"]; [[[stations[1] abbr] should] equal:@"s2"]; [[[stations[1] name] should] equal:@"station two"]; }); }); Thursday, April 18, 13
  46. Arrange, Act, Assert Thursday, April 18, 13

  47. describe(@"Station", ^{ it(@"loads from JSON correctly",^{ NSArray *rawStations = @[

    @{@"abbr":@"s1",@"name":@"station one"}, @{@"abbr":@"s2",@"name":@"station two"}, ]; NSArray *stations = [Station loadStations:rawStations]; [[theValue(stations.count) should] equal:theValue(2)]; [[[stations[0] abbr] should] equal:@"s1"]; [[[stations[0] name] should] equal:@"station one"]; [[[stations[1] abbr] should] equal:@"s2"]; [[[stations[1] name] should] equal:@"station two"]; }); }); Arrange Thursday, April 18, 13
  48. describe(@"Station", ^{ it(@"loads from JSON correctly",^{ NSArray *rawStations = @[

    @{@"abbr":@"s1",@"name":@"station one"}, @{@"abbr":@"s2",@"name":@"station two"}, ]; NSArray *stations = [Station loadStations:rawStations]; [[theValue(stations.count) should] equal:theValue(2)]; [[[stations[0] abbr] should] equal:@"s1"]; [[[stations[0] name] should] equal:@"station one"]; [[[stations[1] abbr] should] equal:@"s2"]; [[[stations[1] name] should] equal:@"station two"]; }); }); ACT Thursday, April 18, 13
  49. describe(@"Station", ^{ it(@"loads from JSON correctly",^{ NSArray *rawStations = @[

    @{@"abbr":@"s1",@"name":@"station one"}, @{@"abbr":@"s2",@"name":@"station two"}, ]; NSArray *stations = [Station loadStations:rawStations]; [[theValue(stations.count) should] equal:theValue(2)]; [[[stations[0] abbr] should] equal:@"s1"]; [[[stations[0] name] should] equal:@"station one"]; [[[stations[1] abbr] should] equal:@"s2"]; [[[stations[1] name] should] equal:@"station two"]; }); }); ASSERT Thursday, April 18, 13
  50. another simple test displaying estimated departure Thursday, April 18, 13

  51. 5 “5 mins” etdToDisplay Thursday, April 18, 13

  52. etdToDisplay 1 “1 min” 5 “5 mins” Thursday, April 18,

    13
  53. etdToDisplay 0 “now” 5 “5 mins” 1 “1 min” Thursday,

    April 18, 13
  54. #import "Kiwi.h" #import "UpcomingDeparture.h" SPEC_BEGIN(UpcomingDepartureSpec) describe(@"[UpcomingDeparture etdToDisplay]", ^{ it(@"is correct

    for an etd of 5",^{ UpcomingDeparture *upcomingDeparture = [[UpcomingDeparture alloc] initWithDestinationName:@"blah" etd:@(5)]; [[[upcomingDeparture etdToDisplay] should] equal:@"5 mins"]; }); }); SPEC_END Thursday, April 18, 13
  55. #import "Kiwi.h" #import "UpcomingDeparture.h" SPEC_BEGIN(UpcomingDepartureSpec) describe(@"[UpcomingDeparture etdToDisplay]", ^{ it(@"is correct

    for an etd of 5",^{ UpcomingDeparture *upcomingDeparture = [[UpcomingDeparture alloc] initWithDestinationName:@"blah" etd:@(5)]; [[[upcomingDeparture etdToDisplay] should] equal:@"5 mins"]; }); it(@"is correct for an etd of 1",^{ UpcomingDeparture *upcomingDeparture = [[UpcomingDeparture alloc] initWithDestinationName:@"blah" etd:@(1)]; [[[upcomingDeparture etdToDisplay] should] equal:@"1 min"]; }); }); SPEC_END Thursday, April 18, 13
  56. #import "Kiwi.h" #import "UpcomingDeparture.h" SPEC_BEGIN(UpcomingDepartureSpec) describe(@"[UpcomingDeparture etdToDisplay]", ^{ it(@"is correct

    for an etd of 5",^{ UpcomingDeparture *upcomingDeparture = [[UpcomingDeparture alloc] initWithDestinationName:@"blah" etd:@(5)]; [[[upcomingDeparture etdToDisplay] should] equal:@"5 mins"]; }); it(@"is correct for an etd of 1",^{ UpcomingDeparture *upcomingDeparture = [[UpcomingDeparture alloc] initWithDestinationName:@"blah" etd:@(1)]; [[[upcomingDeparture etdToDisplay] should] equal:@"1 min"]; }); }); SPEC_END Thursday, April 18, 13
  57. it(@"is correct for an etd of 0",^{ UpcomingDeparture *upcomingDeparture =

    [[UpcomingDeparture alloc] initWithDestinationName:@"blah" etd:@(0)]; [[[upcomingDeparture etdToDisplay] should] equal:@"now"]; }); Thursday, April 18, 13
  58. it(@"is correct for an etd of 0",^{ UpcomingDeparture *upcomingDeparture =

    [[UpcomingDeparture alloc] initWithDestinationName:@"blah" etd:@(0)]; [[[upcomingDeparture etdToDisplay] should] equal:@"now"]; }); Thursday, April 18, 13
  59. edge-cases made easier Thursday, April 18, 13

  60. Wrapping it up Thursday, April 18, 13

  61. Thanks! Questions? Thursday, April 18, 13

  62. Resources • http://slides.thepete.net • http://github.com/allending/Kiwi • the “up and running

    with kiwi” guide • My example BART app on github • NSScreencast on Kiwi (it’s free!) • me: @ph1, http://thepete.net, the bar this slide deck Thursday, April 18, 13