test driven development - pixel.de · • encourages us to write loosely coupled components, so...

52
IT-Development & Consulting it-people it-solutions Michael Karneim, Oliver Kraeft – 19.10.2016 Test Driven Development "Testing shows the presence, not the absence of bugs" Edsger W. Dijkstra, 1969

Upload: others

Post on 24-May-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

IT-Development & Consulting

it-people it-solutions

Michael Karneim, Oliver Kraeft – 19.10.2016

Test Driven Development

"Testing shows the presence, not the absence of bugs"

Edsger W. Dijkstra, 1969

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 2

What Is TDD?

• Automated Tests• Test First

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 3

Why TDD?

• Increase Software Quality

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 4

What Is Software Quality?

• Internal Quality• Product

Characteristics, e.g.– Suitability– Correctness– Reliability– Interoperability– Usability

• Source Code Structure, e.g.– Readability– Maintainability– Extensibility– Testability

• External Quality

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 5

The TDD Cycle

Write a Failing Unit Test

Make the Test Pass

Refactor

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 6

Benefits of TDD Cycle?

• Concentrate on just one task at a time– write test, implement, refactor

• Concentrate on one piece of work– TDD cycle promotes incremental and iterative

development• Progress can (really!) be measured

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 7

Why Test First?

• Writing tests is a design activity– instead of „boring“ work

• Clarify acceptance criteria for next piece of work

• Less risky than „Test Last“

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 8

Why Refactor?

• Developers spend far more time reading code than writing it, so that‘s what we should optimize for.

• It simplifies and improves the design.• It‘s not risky since we already have

regression tests!

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 9

How TDD Gives Feedback About Software Quality

Writing Tests Running Tests

Gives feedback about internal quality

Gives feedback about external quality

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 10

Benefits from Writing Tests

• Makes us clarify the acceptance criteria for the next piece of work – we have to ask ourself how we can tell when we‘re done.

• Encourages us to write loosely coupled components, so they can be tested in isolation and, at a higher level, combined together.

• Executable description of what the code does.• Adds to a complete regression suite.

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 11

Benefits from Running Tests

• Detects errors while the context is fresh in our mind.

• Let‘s us know when we have done enough, discouraging „gold plating“ and unnecessary features.

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 12

How To Start?

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 13

We need a Walking Skeleton!

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 14

What Is a Walking Skeleton?

• It‘s an implementation of the thinnest possible slice of real functionality that we can automatically build, deploy, and test end-to-end.

• Contains all runtime containers (DB, App-Server, Browser, ...)

• Contains mocks of external systems• Contains the deployed application

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 15

The Continuous Integration Cycle

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 16

How to Write Tests?

• Make it easy to read• Make it robust• Make it easy to write• Write it Top Down

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 17

Start with an Acceptance Test

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 18

What‘s an Acceptance Test?

• It‘s part of the specification• Tests features that are visible to the end user• Follows the structure of user stories• It‘s created in collaboration between QA, BA, and

R&D• End-to-End Test• Interacts with the system from the outside

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 19

Gherkin

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 20

Features and Scenarios

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 21

Gherkin Syntax

Feature: Some short but descriptive text of what is desiredin order to realize a named business value

as an explicit system actor.Scenario A: Some determinable business situationGiven: some precondition

and some other preconditionWhen: some action by the actor

and some other action and yet another action

Then: some testable outcome is achieved

and something else we can check happens tooScenario B: A different situation [...]

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 22

Overall Test Structure

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 23

Gherkin: Example Feature

Feature: You can add elements to the list.

Scenario A: Empty List

Scenario B: Populated List (one element)

Scenario C: Populated List (many elements)[...more?]

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 24

Gherkin: Example Scenario

Feature: You can add elements to the list.

Scenario A: Empty List

Given the list is empty.

When the caller adds a new element to this list,

Then the list contains that element. And the number of elements in this list is 1.

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 25

TDD experiences in the past

and in the presence

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 26

TDD experiences in the past - import.sql

INSERT INTO Tabelle1 VALUES (1, ‚aaa‘, 23, ‚2016-10-19)

INSERT INTO Tabelle1 VALUES (2, ‚bbb‘, 24, ‚2016-10-19)

INSERT INTO Tabelle1 VALUES (3, ‚ccc‘, 25, ‚2016-10-19)

INSERT INTO Tabelle1 VALUES (4, ‚ddd‘, 26, ‚2016-10-19)

INSERT INTO Tabelle1 VALUES (5, ‚eee‘, 27, ‚2016-10-19)

INSERT INTO Tabelle1 VALUES (6, ‚fff‘, 28, ‚2016-10-19)

INSERT INTO Tabelle1 VALUES (7, ‚ggg‘, 30, ‚2016-10-19)

INSERT INTO Tabelle1 VALUES (8, ‚hhh‘, 31, ‚2016-10-19)

INSERT INTO Tabelle1 VALUES (9, ‚iii‘, 32, ‚2016-10-19)

INSERT INTO Tabelle1 VALUES (10, ‚jjj‘, 33, ‚2016-10-19)

INSERT INTO Tabelle1 VALUES (11, ‚kkk‘, 34, ‚2016-10-19)

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 27

TDD experiences in the past - confusing tests

@Testpublic void resolveOneLocationTest() {

mockStatic(GeocodingApi.class);String search = "";GeocodingApiRequest geoCodApiRequest = PowerMockito.mock(GeocodingApiRequest.class);

when(geoCodApiRequest.language(any(String.class))).thenReturn(geoCodApiRequest); when(geoCodApiRequest.region(any(String.class))).thenReturn(geoCodApiRequest);

GeocodingResult result1 = new GeocodingResult();final GeocodingResult[] result = new GeocodingResult[] { result1 };try {

when(geoCodApiRequest.await()).thenReturn(result);} catch (Exception e1) {e1.printStackTrace();

}Geometry geometry = new Geometry();LatLng latLng = new LatLng(54.412825, 10.172083);geometry.location = latLng;result1.geometry = geometry;result1.formattedAddress = "formatted address";

when(GeocodingApi.geocode(any(GeoApiContext.class), any(String.class))).thenReturn(geoCodApiRequest);Map<SiteCluster, List<SiteData>> expectedResult = null;try {expectedResult = this.toTest.resolveLocation(search, 20.0);

} catch (Exception e) {e.printStackTrace();fail("No exception expected.");

}assertNotNull("Resultlist is null.", expectedResult);assertEquals("Only one entry expected.", 1, expectedResult.size());for (Entry<SiteCluster, List<SiteData>> entry : expectedResult.entrySet()) {

assertEquals("Wrong area key.", "formatted address", entry.getKey().getLabel());assertEquals("Wrong amount of pharmacies inside area.", 1, entry.getValue().size());

}}

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 28

TDD experiences in the past - ignoring tests

@Ignore

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 29

TDD experiences in the past - problems

• hard to read

• hard to maintain

• failed tests for unknown reason

• one test and many scenarios

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 30

TDD experiences in the presence

@Test@Testing(Feature.Never_accept_cancelled_order)public void testAcceptOrder_does_not_accept_cancelled_orders() {

// Given:Order order = some($Order().withState(OrderState.CANCELLED));

// When:Exception actual = null;try {underTest.accpeptOrder(order);

} catch (Exception ex) {actual = ex;

}

// Then:assertThat(actual).isExactlyInstanceOf(IllegalArgumentException.class);

}

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 31

TDD experiences in the presence - readable method names

testAcceptOrderDoesNotAcceptCancelledOrders()

testAcceptOrder_does_not_accept_cancelled_orders()

test_Methode_Szenario_erwartetes_Ergebnis()

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 32

TDD experiences in the presence - no insignificant details

// GivenString name = "Oliver";String email = "[email protected]";String city = "Gräfelfing";User user = new User(name, email, city);

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 33

TDD experiences in the presence - builder classes

public class UserBuilder {private String name = "Oliver";private email = "[email protected]";private city = "Gräfelfing";

public UserBuilder withName(String name) {this.name = name;return this;

}

public UserBuilder withEmail(String email) {this.email = email;return this;

}

public UserBuilder withCity(String city) {this.city = city;return this;

}

public User build() {User user = new User();user.setName = name;user.setEmail = email;user.setCity = city;return user;

}}

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 34

TDD experiences in the presence - builder classes

User user = new UserBuilder().withEmail("[email protected]").build();

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 35

TDD experiences in the presence - factories and helper

// Namenskonvention: $ bedeutet, die Methode liefert Builderpublic static UserBuilder $User() {

return new UserBuilder().withName("Irgendein Name").withEmail("[email protected]").withCity("München");

}

// Praktische Abkürzung, um Tests flüssiger lesbar zu machenpublic static User a(UserBuilder builder) {

return builder.build();}

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 36

TDD experiences in the presence - readability

User user = a($User().withEmail("[email protected]"));

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 37

TDD experiences in the presence - PojoBuilder

public class User {

@GeneratePojoBuilderpublic User(String name, String email, String city) {

this.name = name;this.email = email;this.city = city;

}}

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 38

TDD experiences in the presence - Asserter

@Testpublic void testPersist_with_items() {// Given:Order order = some($Order().withItems($setOf(several(), $OrderItem())));

// When:db().persist(order);

// Then:Order actual = db().reload(order);assertThat(actual).matches(order);

}

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 39

TDD experiences in the presence - ecstasy

I readable test code

I a lot of details (a(), an(), some())

I fantastic dsl (domain specific language)

I relaxed work because of smaller tasks and security net

I tests are as important as other code

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 40

Integration Test Helper

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 41

Acceptance Test Scenario Example

Feature: Password ManagementScenario: Forgot passwordGiven a user with email „[email protected]

exists.When I ask for a password resetThen an email with a password reset link

should be sent.

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 42

TestBase Provides Help

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 43

Application „Lagerspiegel“

0 Files

175 Files

350 Files

525 Files

700 Files

875 Files

Common Server Planner Client Integration

Java

File

s

Proportion of Main Files to Test Files

Main Test

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 44

Application „Lagerspiegel“

63%

37%

Code Coverage

Lines CoveredLines Uncovered

0 525 1050157521002625

Test / ClassesRatio

Main ClassesTest Methods

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 45

Some Observations (1)

• Code becomes more modularized• We see an inflation of classes• Half of the sources are test code• Class and method names become more

readable• We love the auto-setup functionality for

database and app-server

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 46

Some Observations (2)

• Architectural redesign works like a charm• Introduction of new developers is fast• Close to zero bugs occurred in production

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 47

Some Suggestions (1)

• You must use test data factories, fluent builders and custom assertions to get robust test code.

• Use a good mocking framework and an injection framework to write class level unit tests.

• Call 3rd-party libraries thru a wrapper to simplify tests.

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 48

Some Suggestions (2)

• Think about how to organize your test scenarios in order to find them easily in your code base.

• Use pair programming or code reviews to write tests.

• Use code coverage tools to find untested code.

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 49

So Is TDD the Silver Bullet for Software Engineering?

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de 50

TDD Transforms Software Development into an Empirical Process

2016 PIXEL GmbH - Ein Unternehmen der PIXEL Group - www.pixel.de

• Growing Object Oriented Software Guided by Test

– Steve Freeman, Nat Pryce

• Working Effectivley with Legacy Code

– Michael E. Feathers

Thank You!

51

Zentrale PIXEL GmbHLochhamer Schlag 17D-82166 Gräfelfing

Tel.: +49/89/8 98 68-100Fax: +49/89/8 98 68-111

[email protected]

NiederlassungPIXEL GmbHIm Gewerbepark C15D-93059 Regensburg

© 2016 PIXEL GmbHEin Unternehmen der PIXEL Group