Slide 1

Slide 1 text

Unit testing with Kiwi CocoaConf San Jose 2013 Thursday, April 18, 13

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

Thursday, April 18, 13

Slide 6

Slide 6 text

Thursday, April 18, 13

Slide 7

Slide 7 text

Thursday, April 18, 13

Slide 8

Slide 8 text

Thursday, April 18, 13

Slide 9

Slide 9 text

Thursday, April 18, 13

Slide 10

Slide 10 text

1. write code 2. submit stack of cards 3. wait (probably overnight) 4. find out if your program worked Thursday, April 18, 13

Slide 11

Slide 11 text

Feedback Thursday, April 18, 13

Slide 12

Slide 12 text

write it check it Thursday, April 18, 13

Slide 13

Slide 13 text

feedback Thursday, April 18, 13

Slide 14

Slide 14 text

punchcards 24 hrs Thursday, April 18, 13

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

what’s next? Thursday, April 18, 13

Slide 19

Slide 19 text

of feedback Speed Thursday, April 18, 13

Slide 20

Slide 20 text

of feedback Quality Thursday, April 18, 13

Slide 21

Slide 21 text

syntax vs. semantics Thursday, April 18, 13

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

unit testing means better feedback Thursday, April 18, 13

Slide 25

Slide 25 text

Unit Testing Thursday, April 18, 13

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

x+1 12 13 Thursday, April 18, 13

Slide 28

Slide 28 text

system under test in out Thursday, April 18, 13

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

#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

Slide 32

Slide 32 text

#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

Slide 33

Slide 33 text

#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

Slide 34

Slide 34 text

#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

Slide 35

Slide 35 text

#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

Slide 36

Slide 36 text

Setting up your project with Kiwi Thursday, April 18, 13

Slide 37

Slide 37 text

Guide: Up and Running with Kiwi (on Kiwi’s github wiki) Thursday, April 18, 13

Slide 38

Slide 38 text

or, just use cocoapods Thursday, April 18, 13

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

in out system under test Thursday, April 18, 13

Slide 41

Slide 41 text

[ { “name”:”foo”, ... }, {...} ] Station Station loadStations Thursday, April 18, 13

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

Arrange, Act, Assert Thursday, April 18, 13

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

another simple test displaying estimated departure Thursday, April 18, 13

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

etdToDisplay 1 “1 min” 5 “5 mins” Thursday, April 18, 13

Slide 53

Slide 53 text

etdToDisplay 0 “now” 5 “5 mins” 1 “1 min” Thursday, April 18, 13

Slide 54

Slide 54 text

#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

Slide 55

Slide 55 text

#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

Slide 56

Slide 56 text

#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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

edge-cases made easier Thursday, April 18, 13

Slide 60

Slide 60 text

Wrapping it up Thursday, April 18, 13

Slide 61

Slide 61 text

Thanks! Questions? Thursday, April 18, 13

Slide 62

Slide 62 text

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