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

TDD Workshop Gdansk

TDD Workshop Gdansk

Pawel Dudek

January 24, 2015
Tweet

More Decks by Pawel Dudek

Other Decks in Programming

Transcript

  1. What is a unit test?
    1

    View Slide

  2. Wikipedia, from a book on tests
    “Unit testing is a method by which
    individual units of source code, sets of
    one or more computer program
    modules together with associated
    control data, usage procedures, and
    operating procedures are tested to
    determine if they are fit for use.”
    2

    View Slide

  3. Um… what?
    3

    View Slide

  4. Wikipedia, from a book on tests
    “Unit testing is a method by which
    individual units of source code, sets of
    one or more computer program
    modules together with associated
    control data, usage procedures, and
    operating procedures are tested to
    determine if they are fit for use.”
    4

    View Slide

  5. What is an app?
    5

    View Slide

  6. An app is a set of
    behaviours created by
    programmer and
    expected by user.
    6

    View Slide

  7. We, programmers, have
    a limited cognition. As
    all humans do.
    7

    View Slide

  8. We can’t always ‘load’
    all of the code of our
    app into our memory.
    8

    View Slide

  9. This means that we can,
    by accident, change the
    behaviour of the app.
    9

    View Slide

  10. A

    View Slide

  11. A B

    View Slide

  12. A B

    View Slide

  13. A B
    C

    View Slide

  14. A B
    C

    View Slide

  15. Preserving behaviour of
    complex systems is
    hard. In fact, of any
    system at all.
    15

    View Slide

  16. Enter unit tests.
    16

    View Slide

  17. Unit test is a failsafe to
    make sure app
    behaviour is preserved.
    17

    View Slide

  18. What is a unit test?
    18

    View Slide

  19. Unit tests test smallest
    parts of your code in
    isolation with test code
    19

    View Slide

  20. Unit tests test smallest
    parts of your code in
    isolation with test code
    20

    View Slide

  21. Test isolation
    21

    View Slide

  22. Table Waiter Cook
    processOrder getDishes
    22

    View Slide

  23. I’m
    a cook
    Table Waiter Cook
    processOrder
    getDishes
    Fake cook
    23

    View Slide

  24. Why isolate?
    24

    View Slide

  25. Unit test lifecycle
    25

    View Slide

  26. Unit test lifecycle
    • Arrange
    • Act
    • Assert
    26

    View Slide

  27. When a unit test is not
    a unit test?
    27

    View Slide

  28. When a unit test is not
    a unit test?
    by Michael Feathers
    28

    View Slide

  29. A test is not a unit test if…
    • It talks to a database
    • It communicates across network
    • It touches the file system
    • You have to do special things to your environment
    to run it (edit config files etc)
    29

    View Slide

  30. A test is not a unit test if…
    • It talks to a database
    • It communicates across network
    • It touches the file system
    • You have to do special things to your environment
    to run it (edit config files etc)
    30

    View Slide

  31. A test is not a unit test if…
    • It talks to a database
    • It communicates across network
    • It touches the file system
    • You have to do special things to your environment
    to run it (edit config files etc)
    31

    View Slide

  32. A 100 ms tests is a
    very slow test.
    32

    View Slide

  33. 1500 tests each running 100
    ms. That’s 150 seconds. Two
    and a half minutes.
    33

    View Slide

  34. Where does TDD fit in
    all this?
    34

    View Slide

  35. In TDD you always
    write test first. Always.
    35

    View Slide

  36. TDD is not “just adding
    tests first”. It’s a complete
    workflow.
    36

    View Slide

  37. TDD is a great way to
    “start” when you’re not
    in the zone…
    37

    View Slide

  38. … and way to remind
    yourself what you’ve been
    working on yesterday!
    38

    View Slide

  39. TDD is a great way to
    determine how complex your
    code has become.
    You just have to listen.
    39

    View Slide

  40. Have to fake seven
    objects to isolate test?
    40

    View Slide

  41. Have to inject a fake
    into a fake into a fake?
    41

    View Slide

  42. This always points to an
    overcomplicated design.
    And your tests are here to point
    that out. Very clearly.
    42

    View Slide

  43. By writing test first you’re
    becoming a consumer of
    your upcoming API.
    43

    View Slide

  44. Is that API hard to test?
    44

    View Slide

  45. That means it will probably
    be hard to consume too.
    45

    View Slide

  46. Or it will be really hard to
    maintain.
    46

    View Slide

  47. What unit tests
    can’t do?
    47

    View Slide

  48. Unit tests are never a
    guarantee that you
    won’t ship a bug.
    48

    View Slide

  49. But they’re damn good at
    greatly reducing amount
    of bugs. And time spent
    on QA.
    49

    View Slide

  50. Are unit tests an invaluable tool for
    writing great software? Heck yes.
    Am I going to produce a poor product
    if I can’t unit test? Hell no.
    Jonathan Rasmusson
    50
    http://agilewarrior.wordpress.com/2012/10/06/its-not-about-the-unit-tests/

    View Slide

  51. Specta
    51

    View Slide

  52. Specta
    BDD Testing Framework
    52

    View Slide

  53. Wait what? BDD?
    53

    View Slide

  54. Wait what? BDD?
    Weren’t we supposed to do TDD?
    54

    View Slide

  55. BDD builds upon TDD by formalising
    the good habits of the best TDD
    practitioners.
    Matt Wynne,
    XP Evangelist
    55
    http://blog.mattwynne.net/2012/11/20/tdd-vs-bdd/

    View Slide

  56. Good habits
    56
    • Work outside-in
    • Use examples to clarify requirements
    • Use ubiquitous language
    Thanks Matt!!

    View Slide

  57. Technical stuff now
    57

    View Slide

  58. Specta
    58

    View Slide

  59. Based on XCTest
    59

    View Slide

  60. Minimalistic
    implementation
    60

    View Slide

  61. Syntax
    61

    View Slide

  62. });
    SPEC_END
    SPEC_BEGIN(Example)
    describe(@"Example specs", ^{
    62

    View Slide

  63. });
    SPEC_END
    SPEC_BEGIN(Example)
    describe(@"Example specs", ^{
    63

    View Slide

  64. });
    SPEC_END
    SPEC_BEGIN(Example)
    describe(@"Example specs", ^{
    64

    View Slide

  65. });
    SPEC_END
    SPEC_BEGIN(Example)
    describe(@"Example specs", ^{
    65

    View Slide

  66. });
    SPEC_END
    SPEC_BEGIN(Example)
    describe(@"Example specs", ^{
    it(@“should check compiler sanity", ^{
    expect(YES).to.beTruthy();
    });
    66

    View Slide

  67. Describe/Context
    blocks
    67

    View Slide

  68. Used to make tests more
    readable.
    And isolate behaviour for
    different scenarios.
    68

    View Slide

  69. describe(@"NSNumber", ^{
    describe(@"when created with the default constructor", ^{
    it(@“should have 0 as contained int value", ^{
    NSNumber *number = [[NSNumber alloc] init];
    expect([number integerValue]).to.equal(0);
    });
    });
    context(@"when constructed with an int", ^{
    it(@“should have 42 as contained int value", ^{
    NSNumber *number = [[NSNumber alloc] initWithInt:42];
    expect([number integerValue]).to.equal(42);
    });
    });
    });
    69

    View Slide

  70. You can have
    as many
    nested
    describes as
    you want.
    70

    View Slide

  71. Before/After each
    blocks
    71

    View Slide

  72. afterEach(^{
    appDelegate = nil;
    });
    beforeEach(^{
    appDelegate = [[AppDelegate alloc] init];
    });
    it(@"should have a window", ^{
    expect(appDelegate.window).to.beKindOf([UIWindow class]);
    });
    72

    View Slide

  73. afterEach(^{
    appDelegate = nil;
    });
    beforeEach(^{
    appDelegate = [[AppDelegate alloc] init];
    });
    it(@"should have a window", ^{
    expect(appDelegate.window).to.beKindOf([UIWindow class]);
    });
    1
    2
    3
    73

    View Slide

  74. Hands on!
    Let’s write our very first
    unit test!
    74

    View Slide

  75. Configuring tests
    75

    View Slide

  76. Focusing tests
    76

    View Slide

  77. Focusing tests
    fdescribe(@"Example specs on NSString", ^{
    fit(@"lowercaseString returns a new string with
    everything in lower case", ^{
    fcontext(@"init with damping", ^{
    77

    View Slide

  78. PENDING
    78

    View Slide

  79. PENDING
    it(@"lowercaseString returns a new string with
    everything in lower case", PENDING);
    79

    View Slide

  80. x’ing tests
    80

    View Slide

  81. x’ing tests
    xdescribe(@"Example specs on NSString", ^{
    xit(@"lowercaseString returns a new string with
    everything in lower case", ^{
    xcontext(@"init with damping", ^{
    81

    View Slide

  82. Unit tests results
    82

    View Slide

  83. Unit tests results
    How to understand the output?
    83

    View Slide

  84. Xcode, AppCode,
    Command Line
    All give the same results. Devil is in the details
    84

    View Slide

  85. (…)
    -[SpecSuiteName passing_spec_name]
    Test Case '-[SpecSuiteName passing_spec_name]' started.
    Test Case '-[SpecSuiteName passing_spec_name]' passed
    (0.271 seconds).
    -[SpecSuiteName failling_spec_name]
    Test Case '-[SpecSuiteName failling_spec_name]' started.
    Test Case '-[SpecSuiteName failling_spec_name]' failed
    (0.002 seconds).
    (…)
    Executed 2 tests, with 1 failure (1 unexpected) in 0.273
    (0.278) seconds
    2 tests; 0 skipped; 1 failure; 1 exception; 0 pending
    85

    View Slide

  86. (…)
    -[SpecSuiteName passing_spec_name]
    Test Case '-[SpecSuiteName passing_spec_name]' started.
    Test Case '-[SpecSuiteName passing_spec_name]' passed
    (0.271 seconds).
    -[SpecSuiteName failling_spec_name]
    Test Case '-[SpecSuiteName failling_spec_name]' started.
    Test Case '-[SpecSuiteName failling_spec_name]' failed
    (0.002 seconds).
    (…)
    Executed 2 tests, with 1 failure (1 unexpected) in 0.273
    (0.278) seconds
    2 tests; 0 skipped; 1 failure; 1 exception; 0 pending
    86

    View Slide

  87. (…)
    -[SpecSuiteName passing_spec_name]
    Test Case '-[SpecSuiteName passing_spec_name]' started.
    Test Case '-[SpecSuiteName passing_spec_name]' passed
    (0.271 seconds).
    -[SpecSuiteName failling_spec_name]
    Test Case '-[SpecSuiteName failling_spec_name]' started.
    Test Case '-[SpecSuiteName failling_spec_name]' failed
    (0.002 seconds).
    (…)
    Executed 2 tests, with 1 failure (1 unexpected) in 0.273
    (0.278) seconds
    2 tests; 0 skipped; 1 failure; 1 exception; 0 pending
    87

    View Slide

  88. (…)
    -[SpecSuiteName passing_spec_name]
    Test Case '-[SpecSuiteName passing_spec_name]' started.
    Test Case '-[SpecSuiteName passing_spec_name]' passed
    (0.271 seconds).
    -[SpecSuiteName failling_spec_name]
    Test Case '-[SpecSuiteName failling_spec_name]' started.
    Test Case '-[SpecSuiteName failling_spec_name]' failed
    (0.002 seconds).
    (…)
    Executed 2 tests, with 1 failure (1 unexpected) in 0.273
    (0.278) seconds
    2 tests; 0 skipped; 1 failure; 1 exception; 0 pending
    88

    View Slide

  89. (…)
    -[SpecSuiteName passing_spec_name]
    Test Case '-[SpecSuiteName passing_spec_name]' started.
    Test Case '-[SpecSuiteName passing_spec_name]' passed
    (0.271 seconds).
    -[SpecSuiteName failling_spec_name]
    Test Case '-[SpecSuiteName failling_spec_name]' started.
    Test Case '-[SpecSuiteName failling_spec_name]' failed
    (0.002 seconds).
    (…)
    Executed 2 tests, with 1 failure (1 unexpected) in 0.273
    (0.278) seconds
    2 tests; 0 skipped; 1 failure; 1 exception; 0 pending
    89

    View Slide

  90. Run your tests from
    command line.
    90

    View Slide

  91. Seriously, do.
    It’s pretty awesome.
    91

    View Slide

  92. “Perfect” setup:
    Have your tests run each
    time you change something
    in a file.
    92

    View Slide

  93. Enhance your tests output.
    93

    View Slide

  94. (…)
    -[SpecSuiteName passing_spec_name]
    Test Case '-[SpecSuiteName passing_spec_name]' started.
    Test Case '-[SpecSuiteName passing_spec_name]' passed
    (0.271 seconds).
    -[SpecSuiteName failling_spec_name]
    Test Case '-[SpecSuiteName failling_spec_name]' started.
    Test Case '-[SpecSuiteName failling_spec_name]' failed
    (0.002 seconds).
    (…)
    Executed 2 tests, with 1 failure (1 unexpected) in 0.273
    (0.278) seconds
    2 tests; 0 skipped; 1 failure; 1 exception; 0 pending
    94

    View Slide

  95. 95

    View Slide

  96. Test Output
    xctool vs xcpretty

    View Slide

  97. AppCode
    97

    View Slide

  98. Jon Reid
    “AppCode definitely empowers TDD.
    What I didn't get until I saw someone's
    screencast is to really lean on Extract
    Variable to reduce typing.”
    98

    View Slide

  99. reduce typing
    99

    View Slide

  100. Resources & Contact
    @eldudi
    github.com/mobile-academy/ios-tdd-gdansk
    [email protected]
    Code Examples
    Contact
    100

    View Slide