45
SPL/2010 SPL/2010 Test-Driven Development (TDD) 1

Test-Driven Development (TDD)

  • Upload
    hija

  • View
    30

  • Download
    0

Embed Size (px)

DESCRIPTION

Test-Driven Development (TDD). What is TDD?. changing code without modifying external functional behavior. What is programming?. writing code: addressing requirements/solve a problem verify : code answers requirements / program performs according to specifications - PowerPoint PPT Presentation

Citation preview

Page 1: Test-Driven Development (TDD)

SPL/2010SPL/2010

Test-Driven Development (TDD)

1

Page 2: Test-Driven Development (TDD)

SPL/2010SPL/2010 2

Page 3: Test-Driven Development (TDD)

SPL/2010SPL/2010

What is TDD?

3

changing code without modifying external functional behavior

Page 4: Test-Driven Development (TDD)

SPL/2010SPL/2010

What is programming?● writing code: addressing requirements/solve

a problem● verify: code answers requirements / program

performs according to specifications● requirement/specification/verification:

● complex problem is broken in small problems– can be solved by writing short pieces of code

● specify (define) and verify small pieces of code

4

Page 5: Test-Driven Development (TDD)

SPL/2010SPL/2010

What is Development?●as we develop more, we understand better…

● developer asks better questions, and gets better answers

● requirements of program change over time ● existing code must be changed...

● difficult to predict how other parts of the code are affected

5

Page 6: Test-Driven Development (TDD)

SPL/2010SPL/2010

What is Testing?● correctness – code performs by specification● 3 types of tests:

● Unit tests: a particular module is working properly:– Implemented by the programmer. – Simple test cases for all functions and methods. A test case is

a program…● Integration tests: a combination of modules work well

together and exchange messages according to protocols ● Acceptance tests: a whole system under test to check

that the expected functionality meets the requirements– functional and performance criteria.

6

Page 7: Test-Driven Development (TDD)

SPL/2010SPL/2010

Unit Test Terminology● Test case: tests a single scenario of usage.

● one aspect of the protocol of the object: its invariant, a single pre-condition / post-condition.

● Test suite: collection of test cases that fully verify the public protocol published by an object

● Object under test (OUT): the object being tested by a test suite

● test suite should focus on testing a single object - assuming all other objects perform correctly

7

Page 8: Test-Driven Development (TDD)

SPL/2010SPL/2010

Unit Test Terminology● Test coverage: the part of the code of the object that is

executed by running a test suite● every code line of OUT should be executed when running test suite

● Test fixture: other objects that will interact with the OUT● A test case must be self-contained: create, initialize and set all

the required test fixtures before the test scenario can be executed. Test fixtures must be cleaned up after the test case is run.

● Mockup: a basic, test-specific, implementation for classes on which OUT depends.

● OUT is independent of other objects - avoid using existing objects ● mockup and the "real" object will usually satisfy the same interface● Usually: mockup for data-retrieval, not for logical behavior

8

Page 9: Test-Driven Development (TDD)

SPL/2010SPL/2010

Unit Test Terminology● Positive test case: verifies that a public

operation of the OUT performs as expected.● Negative test case: verifies that a public

operation of the OUT fails as expected – a call to a method when a pre-condition does not hold

properly throws an exception● Repeatable and deterministic tests: runs

the same test twice in a row - same result. ● test case cannot depend on external data or on

the timing of RTE scheduler 9

Page 10: Test-Driven Development (TDD)

SPL/2010SPL/2010

Pseudocode exampleset_hour (a_hour: INTEGER)

-- Set `hour' to `a_hour' require

valid_argument: 0 <= a_hour and a_hour <= 23 do

hour := a_hour ensure

hour_set: hour = a_hour end

10

precondition

postcondition

Page 11: Test-Driven Development (TDD)

SPL/2010SPL/2010

TDD = TFD+refactor

11

Page 12: Test-Driven Development (TDD)

SPL/2010SPL/2010

What is TDD?● Test first design - repeatedly first

writing a test case and then implementing the code necessary to pass the test.

● It is the responsibility of the programmer to define the unit tests as part of the code delivery● requirements granularity level of the module ● module depends on other modules

12

Page 13: Test-Driven Development (TDD)

SPL/2010SPL/2010

What is TDD?● requirements on the code by writing a

test● test case IS the expression of the

requirement● implement code to stand by the

requirements● code pass tests

13

Page 14: Test-Driven Development (TDD)

SPL/2010SPL/2010

Test First Design cycle● Define objects: responsible for specific functionality and interaction● Write tests for each OUT:

● Define the interface of the OUT● Define  contract for each method of the OUT interface● Specify pre-conditions, post-conditions for each method and invariant for

the OUT. ● Write test cases for each invariant, pre and post-condition of each method in the

interface.● Write the code so it will pass the test● Run tests● Refactor! improve code design by removing code that "looks bad“ ("code

smells“)● Repeat process: code changes, rules change, test change● When needed - Break the contract, Redefine tests, Refactor code

14

Page 15: Test-Driven Development (TDD)

SPL/2010SPL/2010

Design By Contract (DBC)

Concept that helps programmers express the requirements on an object, correctness criteria:● preconditions : things that must be true

before we invoke a method● postconditions : things that must be true

after a method is invoked● invariants: things that must be true both

before and after a method is invoked

15

Page 16: Test-Driven Development (TDD)

SPL/2010SPL/2010

TDD benefits●  validation of correctness: errors caused by code/design

modifications are caught quickly by programmer, immediately after the code is changed.

● courage to make code modifications and refactoring, a change will "break" the program.

● integration tests - test cases can help design intelligent integration tests.

● design improvement- writing tests before the OUT is implemented ensures OUT is indeed usable, that it is easy to prepare the context in which the OUT can be invoked.

● E.g.: OUT depends on too many other objects or global objects, - writing tests becomes very difficult - test cases reveal this - strong incentive to improve the design of the OUT

● documentation - test classes provide examples of code usage

16

Page 17: Test-Driven Development (TDD)

SPL/2010SPL/2010

JUnitJunit: a simple framework to write tests (in Eclipse) ● public default ctor● setUp() - prepare pre-conditions (@Before)● tearDown() - "clean up" the test object after a test has run

(@After), "undoes" what the @Before method did.● test method for each test case (@Test)

● JUnit run:● instance of the test class is constructed.● run setUp()● run test case● display test results (pass/fail)● run tearDown()

17

Page 18: Test-Driven Development (TDD)

SPL/2010SPL/2010

Example: Stack data object

18

Page 19: Test-Driven Development (TDD)

SPL/2010SPL/2010

TDD● Requirement: write a simple Stack data

object, what is a "Stack"?● informal description:

● Stack is a container of Objects. ● Objects are ordered in Last-In-First-Out order. ● Add/Remove an Object to Stack

19

Page 20: Test-Driven Development (TDD)

SPL/2010SPL/2010

Interface

Turn Description into interface (formalize )

20

Javadoc: inline tag {@link URL}

Page 21: Test-Driven Development (TDD)

SPL/2010SPL/2010

Generics● it is a "code smell", to let a container

receive any object (too general)… ● Object = haven't thought enough about

specific objects

21

Page 22: Test-Driven Development (TDD)

SPL/2010SPL/2010

fill interface – what means to use a Stack?

● DBC: methods, preconditions, postconditions, invariants

22

Page 23: Test-Driven Development (TDD)

SPL/2010SPL/2010

test class● test-class skeleton for the interface

23

Page 24: Test-Driven Development (TDD)

SPL/2010SPL/2010

define tests● think of complicated scenarios/ usage:

parameters, exceptions, return values● think of complicated behavior/sequences:

– push-pop-pop, pop-Exception – isEmpty returns true or false, – push objects of different types <T>

● push a null - What should we do?● Change Stack API, - add Exception to push()● do not change interface - specify in Javadoc

expected behavior24

Page 25: Test-Driven Development (TDD)

SPL/2010SPL/2010

Implement tests● TFD: think of tests BEFORE implementing● define Stack<Integer>● assume "this.stack" is already

instantiated● add @Before method to create the stack

25

Page 26: Test-Driven Development (TDD)

SPL/2010SPL/2010

first tests

26

Page 27: Test-Driven Development (TDD)

SPL/2010SPL/2010 27

Page 28: Test-Driven Development (TDD)

SPL/2010SPL/2010

more complex tests

28

Page 29: Test-Driven Development (TDD)

SPL/2010SPL/2010 29

Page 30: Test-Driven Development (TDD)

SPL/2010SPL/2010

implement Stack interface● write minimum! code to pass tests

● if no test fails, we don't need to write code● passing code is valid Stack implementation.

● additional classes require their test cases● Tip: override (and test) toString method,

for all classes

30

Page 31: Test-Driven Development (TDD)

SPL/2010SPL/2010

Refactoring tests● test (positive) for push()

● pop() to test push() – circular● pop() changes the state of the stack

(removes top item)

31

Page 32: Test-Driven Development (TDD)

SPL/2010SPL/2010

Refactoring tests● Weak pop() test: - push an item and pop without exception● Better test:

● returns last element pushed on the stack;● stack has one element less● … a copy of testPush() - one test for two functions

● …complex post-conditions - rethink! - analyze contract of pop() ● pop() does 2 things:

● removes an item from the stack ● returns the value of this item.

● design (if possible) methods to do one thing - reusable, testable.

32

Page 33: Test-Driven Development (TDD)

SPL/2010SPL/2010

Refactoring tests:6 principles for writing testable interfaces

1. Separate commands and queries:● Queries return a value and do not change

the visible state of the object– methods with side-effect on the object - push()

● Commands change the internal state of the object and do not return values– functions that only get information - isEmpty()

33

Page 34: Test-Driven Development (TDD)

SPL/2010SPL/2010

Refactor pop()● pop() does not stand by this rule: it is

neither a command nor a query● replace pop() with primitive methods:

● top() returns the value of the top object● remove() removes top object from the stack

● keep pop():● T pop() { T top = top(); remove(); return top; }

34

Page 35: Test-Driven Development (TDD)

SPL/2010SPL/2010 35

Page 36: Test-Driven Development (TDD)

SPL/2010SPL/2010

2. Separate Basic Queries from Derived Queries

● Is this test strong enough? What could go wrong?

● Change hats: assume person writing the code tries to pass the test with minimal effort● push=replace● testStackLIFO – 3 item stack

36

Page 37: Test-Driven Development (TDD)

SPL/2010SPL/2010

● count() – add new query that indicates how many elements are stored in Stack

use to write post-conditionof push(), remove()

● @pre(count()) - refer to value of count() before command is executed

● isEmpty(): count()==0● count() - primitive query● isEmpty() - derived query ● post-condition computed

based on primitive query

37

Page 38: Test-Driven Development (TDD)

SPL/2010SPL/2010

2. Separate basic and derived queries● Derived queries can be specified in terms of

basic queries.3. Define derived queries in terms of

basic queries● Define the post-conditions of derived queries

in terms of basic queries only

38

Page 39: Test-Driven Development (TDD)

SPL/2010SPL/2010

4. For each basic command, write post-conditions that specify values of basic queries

● a command modifies the state of OUT● test modification, with basic queries:

● review post-conditions of command by available basic queries of object

● if no basic queries is affected – extend/revise interface

● isEmpty() is a derived query (count()) – can be removed

39

Page 40: Test-Driven Development (TDD)

SPL/2010SPL/2010

Refactor remove()● contract encoded in the pre, post-

conditions ● remove() removes one element from stack● cannot call when the stack is empty. ● WHICH element is removed (top)?● more specific contract● basic observe query

40

Page 41: Test-Driven Development (TDD)

SPL/2010SPL/2010 41

Page 42: Test-Driven Development (TDD)

SPL/2010SPL/2010

● Did this make our post-condition for remove() stronger?

● count() has been decreased by one● Do we need to check that the last element is

the one that is removed?● itemAt for all values of i=1 to new count() are not

affected● Did itemAt() break encapsulation?

● stack limit access to only the top element

42

Page 43: Test-Driven Development (TDD)

SPL/2010SPL/2010

5. For each basic command and query, express pre-conditions in terms of basic queries

● reminder: basic queries are sufficient to capture post-conditions of basic commands

43

Page 44: Test-Driven Development (TDD)

SPL/2010SPL/2010

6. Specify class invariants that impose “always true” constraints on basic queries

●  class invariants: properties that remain true in all legal states: @inv count() >= 0

● verify contract of commands that affect count() cannot break this invariant. ● remove() : verify that the pre-condition

prevents count() from changing from 0 to -1

44

Page 45: Test-Driven Development (TDD)

SPL/2010SPL/2010

Summary● specify the interface of objects before implement ● interface specification includes contract for methods, expressed in

terms of @pre, @post and @inv conditions.● write tests for interface to verify contract is enforced before

implementation● design objects interface to be testable:

● Separate commands and queries.● Separate basic queries and derived queries.● Define derived queries in terms of basic queries.● For each basic command, write post-conditions that specify values of basic

queries● For each basic command and query, express the pre-conditions in terms of

basic queries.● Specify class invariants that impose “always true” constraints on basic queries

45