0% found this document useful (0 votes)
8 views16 pages

13 TestDrivenDevelopment

Test-driven development (TDD) is a software development process that relies on the repetition of short development cycles. Each cycle involves writing a test, making it pass by writing just enough code, and refactoring the code. This is intended to increase code quality and prevent bugs. The document discusses the TDD process, test frameworks, mock objects, refactoring code to improve design, and reasons for and against refactoring.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views16 pages

13 TestDrivenDevelopment

Test-driven development (TDD) is a software development process that relies on the repetition of short development cycles. Each cycle involves writing a test, making it pass by writing just enough code, and refactoring the code. This is intended to increase code quality and prevent bugs. The document discusses the TDD process, test frameworks, mock objects, refactoring code to improve design, and reasons for and against refactoring.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 16

Test-Driven Development

and
Refactoring

CPSC 315 – Programming Studio


Testing

Discussed before, general ideas all still hold


Test-Driven Development
 Generally falls under Agile heading
 A style of software development, not just a matter
of testing your code
 Enforces testing as part of the development
process
Test Driven Development
Overview

Repeat this process:
1. 1. Write a new test
2. 2. Run existing code against all tests; it
should generally fail on the new test
3. 3. Change code as needed
4. 4. Run new code against tests; it
should pass all tests
5. 5. Refactor the code
Test Writing First

Idea is to write tests, where each test
adds some degree of functionality

Passing the tests should indicate
working code (to a point)

The tests will ensure that future
changes don’t cause problems
Running Tests

Use a test harness/testing framework of
some sort to run the tests
 A variety of ways to do this, including
many existing frameworks that support
unit tests
 JUnit is the most well-known, but there is
similar functionality across a wide range of
languages
Test framework

Specify a test fixture
 Basically builds a state that can be tested
 Set up before tests, removed afterward

Test suite run against each fixture
 Set of tests (order should not matter) to verify various
aspects of functionality
 Described as series of assertions

Runs all tests automatically
 Either passes all, or reports failures

Better frameworks give values that caused failure
Mock Objects

To handle complex external queries
(e.g. web services), random data, etc.
in testing

Implements an interface that provides
some functionality
 Can be complex on their own – e.g.
checking order of calls to some object,
etc.
 Can control the effect of the interface
Example Mock Object

Remote service
 Interface to authenticate, put, get
 Put and Get implementations check that
authentication was called
 Get verifies that only things that were “put” can be
gotten.

As opposed to an interface that just returned
valid for authenticate/put, and returned fixed
value for get.
Successful Tests

Tests should eventually pass

You need to check that all tests for that
unit have passed, not just the most
recent.
Checklist: Test Cases

Does each requirement that applies to the class or routine have its own test case?

Does each element from the design that applies to the class or routine have its own test case?

Has each line of code been tested with at least one test case?

Has this been verified by computing the minimum number of tests necessary to exercise each line of
code?

Have all defined-used data-flow paths been tested with at least one test case?

Has the code been checked for data-flow patterns that are unlikely to be correct?

Defined-defined, defined-exited, defined-killed, etc.

Has a list of common errors been used to write test cases to detect errors that have occurred frequently in the
past?

Have all simple boundaries been tested: maximum, minimum, off-by-one?

Have compound boundaries been tested: combinations of input data that might result in a computed variable
that is too small or too large?

Do test cases check for the wrong kind of data?

Are representative, middle of the road values tested?

Are the minimum and maximum normal configurations tested?

Is compatibility with old data tested?

Do test cases make hand-checks easy?
Refactoring

As code is built, added on to, it
becomes messier

Need to go back and rewrite/reorganize
sections of the code to make it cleaner

Do this on a regular basis, or when
things seem like they could use it

Only refactor after all tests are passing
 Test suite guarantees refactoring doesn’t
hurt.
Reasons to Refactor

Code is duplicated

A routine is too long

A loop is too long, or too deeply nested

A class has poor cohesion

A class interface does not provide a consistent level of
abstraction

A parameter list has too many parameters

Changes within a class tend to be compartmentalized

Changes require parallel modifications to multiple classes

Inheritance hierarchies have to be modified in parallel

Case statements have to be modified in parallel

OMG this list is long!!! (see page 565 – 570 in Code Complete)
Reasons Not to Refactor

None?


Don’t use refactoring as a cover for code and
fix.

Refactoring is changes in working code
that do not affect behavior.

Avoid refactoring instead of rewriting.

Sometimes code just needs to be
redesigned and reimplemented.
Refactoring
Common Operations

Extract Class

Extract Interface

Extract Method

Replace types with subclasses

Replace conditional with polymorphic objects

Form template

Introduce “explaining” variable

Replace constructor with “factory” method

Replace inheritance with delegation

Replace magic number with symbolic constant

Replace nested conditional with guard clause
When to Refactor

Consider refactoring after you

Add a routine

Add a class

Fix a defect

Touch anything in the code

Target error-prone and high complexity
modules.
Resources

Test-Driven Development By Example
 Kent Beck; Addison Wesley, 2003

Test-Driven Development A Practical Guide
 David Astels; Prentice Hall, 2003

Software Testing A Craftsman’s Approach
(3rd edition)
 Paul Jorgensen; Auerback, 2008


Many other books on testing, TDD, also

You might also like