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

TDD Workshop

TDD Workshop

Introduction to tests, TDD and Specta testing framework.

Pawel Dudek

April 26, 2014
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?

    View Slide

  4. What is an app?
    4

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  10. Enter unit tests.

    View Slide

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

    View Slide

  12. What is a unit test?

    View Slide

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

    View Slide

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

    View Slide

  15. Test isolation

    View Slide

  16. Table Waiter Cook
    processOrder getDishes

    View Slide

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

    View Slide

  18. Why isolate?

    View Slide

  19. Unit test lifecycle
    19

    View Slide

  20. Unit test lifecycle
    • Arrange
    • Act
    • Assert

    View Slide

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

    View Slide

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

    View Slide

  23. 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)

    View Slide

  24. 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)

    View Slide

  25. 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)

    View Slide

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

    View Slide

  27. A 100 ms tests is a
    very slow test.
    Thus touching file system, network,
    database etc is a no no.

    View Slide

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

    View Slide

  29. Where does TDD fit in
    all this?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  35. Have to fake seven
    objects to isolate test?

    View Slide

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

    View Slide

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

    View Slide

  38. What unit tests
    can’t do?
    38

    View Slide

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

    View Slide

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

    View Slide

  41. 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
    41
    http://agilewarrior.wordpress.com/2012/10/06/its-not-about-the-unit-tests/

    View Slide

  42. Specta
    42

    View Slide

  43. Specta
    BDD Testing Framework

    View Slide

  44. Wait what? BDD?

    View Slide

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

    View Slide

  46. BDD builds upon TDD by formalising
    the good habits of the best TDD
    practitioners.
    Matt Wynne,

    XP Evangelist
    46
    http://blog.mattwynne.net/2012/11/20/tdd-vs-bdd/

    View Slide

  47. Good habits
    47
    • Work outside-in

    • Use examples to clarify requirements

    • Use ubiquitous language
    Thanks Matt!!

    View Slide

  48. Technical stuff now

    View Slide

  49. Based on XCTest

    View Slide

  50. Minimalistic
    implementation

    View Slide

  51. Syntax

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  57. Describe/Context
    blocks
    57

    View Slide

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

    View Slide

  59. 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);
    });
    });
    });

    View Slide

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

    View Slide

  61. Before/After each
    blocks
    61

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  65. Configuring tests
    65

    View Slide

  66. Focusing tests

    View Slide

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

    View Slide

  68. PENDING

    View Slide

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

    View Slide

  70. x’ing tests

    View Slide

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

    View Slide

  72. Unit tests results
    72

    View Slide

  73. Unit tests results
    How to understand the output?

    View Slide

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

    View Slide

  75. (…)
    !
    -[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

    View Slide

  76. (…)
    !
    -[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

    View Slide

  77. (…)
    !
    -[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

    View Slide

  78. (…)
    !
    -[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

    View Slide

  79. (…)
    !
    -[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

    View Slide

  80. Run your tests from
    command line.

    View Slide

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

    View Slide

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

    View Slide

  83. Tip:
    Use xctool

    View Slide

  84. AppCode
    84

    View Slide

  85. 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.”

    View Slide

  86. reduce typing

    View Slide

  87. Resources & Contact
    @eldudi
    github.com/paweldudek
    [email protected]
    Code Examples
    Contact
    87

    View Slide