Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

28
© 2013 Tieto Corporation TDD – from dreams to reality Saulius Narkevičius. Viačeslav Pozdniakov.

description

 

Transcript of Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

Page 1: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

TDD – from dreams to realitySaulius Narkevičius. Viačeslav Pozdniakov.

Page 2: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2013 Tieto Corporation

Programming architect(~ 23 years of programing)

University lector

Assembler, …, Java, ...

Desktop / Web

UI / Middleware / Database

Waterfall / Agile / Whatever

Saulius Viačeslav

24 hours developer(~ 9 years of programing)

University lector

Scala, Haskell, Java, ...

Desktop / Web

Databases / Middleware

Agile / Whatever

Page 3: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Three TDD steps

1. Failing test 2. Production code

3. Refactor

Page 4: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2013 Tieto Corporation

TDD dreamFast feedback

Drives simple code design

DocumentationKeeps

developers head “empty” –

everything is in code

Safety net for refactoring

Page 5: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Super feature request:

“Calculate average of two integer values”

Page 6: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

int averageOf(int a, int b) { return (a + b) / 2; }

Java solution 20 seconds later

Page 7: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

1. Red – write a failing test @Test public void smokeTestAverage() { assertThat(averageOf(2, 4), is(3)); }

Does not compile – No averageOf() exists yet!

Page 8: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

2. Green – just enough production code

Test passes successfully

@Test public void smokeTestAverage() { assertThat(averageOf(2, 4), is(3)); }

int averageOf(int a, int b) { return 3; }

Page 9: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

3. Refactor – make code cleaner

Nothing to refactor yet

@Test public void smokeTestAverage() { assertThat(averageOf(2, 4), is(3)); }

int averageOf(int a, int b) { return 3; }

Page 10: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Repeat: red, green, refactor

Hmm, code is really dumb…

@Test public void smokeTestAverage() { assertThat(averageOf(2, 4), is(3)); assertThat(averageOf(10, 20), is(15)); }

int averageOf(int a, int b) { return (a == 10) ? 15 : 3; }

Page 11: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Let’s triangulate

Done!!! Took longer with tests :(

@Test public void smokeTestAverage() { assertThat(averageOf(2, 4), is(3)); assertThat(averageOf(10, 20), is(15)); assertThat(averageOf(-8, -16), is(-12)); }

int averageOf(int a, int b) { return (a + b) / 2; }

Page 12: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Edge cases

FAILED: Expected 2147483647 but was -1

@Test public void edgeCasesForAverage() { assertThat(averageOf(MAX, MAX), is(MAX)); assertThat(averageOf(MIN, MIN), is(MIN)); }

int averageOf(int a, int b) { return (a + b) / 2; }

Page 13: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Avoid overflow by using subtraction

Tests pass successfully

@Test public void edgeCasesForAverage() { assertThat(averageOf(MAX, MAX), is(MAX)); assertThat(averageOf(MIN, MIN), is(MIN)); }

int averageOf(int a, int b) { int high = (a > b ? a : b); int low = (a > b ? b : a); return low + ((high - low) / 2); }

Page 14: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

One more edge case

FAILED: Expected 0 but was -2147483648

@Test public void edgeCasesForAverage() { assertThat(averageOf(MAX, MAX), is(MAX)); assertThat(averageOf(MIN, MIN), is(MIN)); assertThat(averageOf(MIN, MAX), is(0)); }

int averageOf(int a, int b) { int high = (a > b ? a : b); int low = (a > b ? b : a); return low + ((high - low) / 2); }

When to stop?

Page 15: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2013 Tieto Corporation

When TDD shines

→ Clear requirements

→ Requirements do not change every hour

→ Sample tests are in place

→ Test execution is fast and one click away

→ Testing environment similar to production.

Page 16: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2013 Tieto Corporation

TDD in the real world

→ What to test?

→ Building data sets for tests

→ Sample tests to start from

→ Legacy code may not be testable

→ What not to test?

Page 17: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2013 Tieto Corporation

“What to test?” is a wrong question

→ We are not testing but specifying sample usage scenarios

→ What do you want to specify / describe?

→ Testing frameworks speak “Specs”:• RSpec, Cucumber, Jasmine, Concordion, ...

→ TDD thought leaders done this years ago:• Dan North, Dave Astels, Robert C Martin (a.k.a. Uncle Bob), ...

→ Naming is everything (see: Specification by Example)

Page 18: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Sample test @Test public void testCreatBookWithFullData() { tester.login(); tester.startPage(BookEditPage.class); FormTester formTester = tester.newFormTester("newBookForm"); formTester.setValue("main.container:title", “Some book title"); formTester.setValue("main.container:author", “Some author"); formTester.setValue("main.container:year", "1999"); formTester.setValue("main.container:publisherPageUrl", "www.newBook.lt"); formTester.setValue("main.container:pages", "222"); formTester.setValue("main.container:publisherName", “Some publisher"); formTester.setValue("main.container:series", “Very interesting series"); formTester.setValue("main.container:originalName", “some original name"); formTester.submit("submit"); tester.assertRenderedPage(BookPage.class); tester.assertLabel("title", " Some book title"); tester.assertLabel("authorPanel:authors:0:author.link:author", "Some author"); tester.assertContains("some original name"); tester.assertLabel("years.link:year", "1999"); tester.assertLabel("publisher.link:publisher.name", "Some publisher"); tester.assertLabel("pages", "222");

}

Do not read this code

Page 19: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Same test as spec

public void creating_new_book_scenario() { givenCurrentUserIsAnAdministrator(); Book newBook = createNewBook(); show(BookEditPage.class); fillFormFieldsWith(newBook);

submitForm();

expectCurrentPageIs(BookPage.class); expectCurrentPageDisplaysAttributesOf(newBook); }

Page 20: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Data sets for specs // create or load from test DB

interface TypicalUsers { User admin(); User guest(); User reviewer(); User author(); } interface TypicalBooks { Book basicBook(); Book bookWithThreeAuthors(); Book bookWithReview(); }

Page 21: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Sample spec for persistence @Test public void orm_mappings_are_ok () { loadAndPrintSomeEntitiesOf(Book.class); }

Page 22: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Sample spec for UI @Test public void renders_successfully() { new WicketTester().startPage(NewClientPage.class); }

Page 23: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Sample spec for business logic (WS)@Test public void extending_book_loan() { process(requestToBookLoanHandler(”extend_loan_request.xml")); expectResponse(”loan_approved_response.xml");}

Page 24: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2013 Tieto Corporation

Writing testable code

Is writing tests easy?

Yes, it is.

The art is in writing testable production code!

→ See short guide: “Writing Testable Code”

Page 25: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2013 Tieto Corporation

What not to specify: technical viewpoint

→Getters, setters and member variables

→One line functions

→GUI – make as thin and dumb as possible

→Frameworks – things you do not control

→Things which are hard to code - by trial and error.

Page 26: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2013 Tieto Corporation

What not to specify:process viewpoint

→Accelerated Agile – buzzword from Dan North

→Some ingredients of accelerated agile:• developers become domain experts• short iterations (days, hours) – less chance for bugs• deliver as soon as possible – even without specs• discover knowledge from real usage

→ Write specs for code which survived real usage

→Works for some projects

Page 27: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

TDD:from DREAMS to

REALITY

Think “specs”

not “tests”

Know what to specify

Use TDD wisely

Real specs come from real usage

Know what not to

specify

Simple smoke specs are a

good investment

Simplify writing specs by “Writing Testable Code”

Page 28: Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)

© 2

013

Tie

to C

orpo

ratio

n

Questions?