Vous êtes sur la page 1sur 55

Presenting TDD

TEST-DRIVEN DEVELOPMENT

2009-04-29

Brian Rasmussen
http://www.linkedin.com/in/brianrasmussen

AGENDA

Answers to the WH-words

Where to begin

The Turn

the Twist

Excuses and Common Traps

Where to go from here

(WHO WHAT WHERE)

What is TDD

WHAT IS TDD

Test-Driven Development (or test driven design) is


a methodology.

Common TDD misconception:


TDD is not about testing

TDD is about design and development

By testing first you design your code

WHAT IS TDD

Short development iterations.

Based on requirement and pre-written test cases.

Produces code necessary to pass that iteration's


test.

Refactor both code and tests.

The goal is to produce working clean code that


fulfills requirements.

TEST-DRIVEN DEVELOPMENT

Test-driven development (TDD) is a software


development technique that uses short
development iterations based on pre-written test
cases that define desired improvements or new
functions. Each iteration produces code necessary
to pass that iteration's tests. Finally, the
programmer or team refactors the code to
accommodate changes. A key TDD concept is that
preparing tests before coding facilitates rapid
feedback changes. Note that test-driven
development is a software design method, not
merely a method of testing.

HOW DOES TDD HELP

TDD helps you produce clean working code that


fulfills requirements

Write Test Code

Write Functional Code

Code that fulfills requirements


Working code that fulfills requirements

Refactor

Clean working code that fulfills requirements

ORIGIN

eXtreme Programming (XP)

1999 Kent Beck, Martin Fowler and others

TDD BASICS - UNIT TESTING

Red, Green, Refactor

Make it Fail

Make it Work

No code without a failing test


As simply as possible

Make it Better

Refactor

TDD CYCLE

Make it Better

Make it Fail

Make it Work

TDD CYCLE

Write Test Code

Guarantees that every functional code is testable


Provides a specification for the functional code
Helps to think about design
Ensure the functional code is tangible

Write Functional Code

Fulfill the requirement (test code)


Write the simplest solution that works
Leave Improvements for a later step
The code written is only designed to pass the test

no further (and therefore untested code is not created).

Refactor

Clean-up the code (test and functional)


Make sure the code expresses intent
Remove code smells
Re-think the design
Delete unnecessary code

Why TDD

WHY / BENEFITS

Confidence in change

Increase confidence in code


Fearlessly change your code

Document requirements

Discover usability issues early

Regression testing = Stable software = Quality


software

WHERE DOES IT HURT


The pain is here!
100%

This is too late


10000
9000

80%

8000
7000

60%

6000
5000

% defects created

40%

4000
3000

20%

Thousand $s

2000
1000

0%

% of Defects Introduced

Cost to Fix a Defect

IS TDD A WASTE OF TIME

(MICROSOFT RESEARCH)

160%
140%
120%
100%
80%
60%
40%
20%
0%

Time To Code Feature


Time To Code Feature
using TDD
Defect density of
team
Defect density of
team using TDD

Major quality improvement for minor time


investment

How to

REMEMBER - THERE ARE OTHER KINDS OF


TESTS

Unit test (Unit)


Integration test (Collaboration)
User interface test (Frontend, ex. WatiN)
Regression test (Continuous Integration)
, System, Performance, Stress, Usability,

The only tests relevant to TDD is Black-box Unit


Testing
Test types:
Black-box test
White-box test

DIFFICULT SCENARIOS TO UNIT TEST

Closed Object Models (Sharepoint, Silverlight)


Client server architecture

An out-of-process call

Includes talking to databases and Web Services.

UI

Communicating Across a Network

GUI interaction

Touching the File System


Legacy Code
Requires the Environment to be configured

HOW TO DO TDD

on my component A?
Unit Test A, but what about B, C, D?

HOW TO DO TDD
on my component A?
This, and the previous two slides,
all thoughts
on reference
implementing tests on existing
are
If my
component

My coworkers component code.

A third party component

A very slow component (Database, Web service)


This
is all White-box Unit- or Integration

A component with complex set up


has therefore
nothing
to do with

Aand
component
with exceptional
behavior (Exception)

A remote component (Remoting)

Circular dependency

Testing
TDD.

In TDD you write a Black-box Unit test that fails,


first,
Do I worry
have to
waitthe
on these
components to be
and
about
code implementation
later.
created and/or tested?

SINGLE MOST IMPORTANT THING


WHEN LEARNING TDD

Do not
write the code in your
head
before you write the test

SINGLE MOST IMPORTANT THING


WHEN LEARNING TDD

When you first start at doing TDD you "know" what


the design should be. You "know" what code you want
to write. So you write a test that will let you write that
bit of code.
When you do this you aren't really doing TDD since
you are writing the code first (even if the code is only
in your head )
It takes some time to (and some poking by clever folk)
to realize that you need to focus on the test. Write the
test for the behavior you want - then write the
minimal code needed to make it pass - then let the
design emerge through refactoring. Repeat until done.

Where to begin

UNBOUNDED STACK EXAMPLE

Requirement: FILO / LIFO messaging system

Brainstorm a list of tests for the requirement:

Create a Stack and verify that IsEmpty is true.


Push a single object on the Stack and verify that IsEmpty is false.
Push a single object, Pop the object, and verify that IsEmpty is true.
Push a single object, remembering what it is; Pop the object, and verify
that the two objects are equal.
Push three objects, remembering what they are; Pop each one, and verify
that they are removed in the correct order.
Pop a Stack that has no elements.
Push a single object and then call Top. Verify that IsEmpty is false.
Push a single object, remembering what it is; and then call Top. Verify that
the object that is returned is the same as the one that was pushed.
Call Top on a Stack with no elements.

UNBOUNDED STACK EXAMPLE

Choosing the First Test?

The simplest.
The essence.

Answers:
If you need to write code that is untested, choose a
simpler test.

If the essence approach takes to much time to


implement, choose a simpler test.

UNBOUNDED STACK EXAMPLE

Anticipating future tests, or not?

Answers:
In the beginning, focus on the test you are writing,
and do not think of the other tests.

As you become familiar with the technique and the


task, you con increase the size of the steps.

But remember still, no written code must be


untested.

Unbounded stack
example

UNBOUNDED STACK EXAMPLE

As we were implementing the sixed test, a few


additional tests came to mind, so we need to add
them to our test list.
We want to add tests to verify that the Stack works
when the arguments are equal to null. The new
tests are as follows:

Push null onto the Stack and verify that IsEmpty returns false.
Push null onto the Stack, Pop the Stack, and verify that the value
returned is null.
Push null onto the Stack, call Top, and verify that the value returned is
null.

The Turn

WHY DONT YOU DO TDD, STILL

Why, when TDD was born a decade ago?

The one and only reason: #1: Learning curve

So why am I telling you this today?

Something happened in the last year

TECHNIQUES YOU NEEDED TO KNOW ABOUT

Interfaces
Dependency Injection
Test Doubles (Mock Objects)
Mocking Framework.
The builder and fluent interface patterns.

Not a chance you still need to know about:


Refactoring

THE OLD WAY VS THE NEW WAY


Either (the old way)
Mock
Using Interfaces, Dependency Injection and
Test Doubles (Mock Objects)
Or (the new way)
Isolate and Fake
Using Typemock Isolator
and AAA - The "Arrange-act-assert" pattern

WHY ISOLATE AND / OR FAKE AT ALL


when you can hand-writemocks yourself.

ASP.NET MVC example

WHY ISOLATE AND / OR FAKE AT ALL


when you can hand-writemocks yourself.

ASP.NET MVC

Rewriting all this with Isolator code

AccountControllerTest file contains 25 tests.


It's a waste of time.
The mocking code starts at line 376 and goes on until line 668 (the end
ofStart
the file).
That's 293
of mocking
code, some of it
contains logic.
using
an lines
isolation
framework
now.

Ends at line 392

I'll let you do the math.

I wrote mock code like that before. Can you believe my mocking code
even contained bugs? I had to fix those as well.

WHY BUY WHEN YOU CAN GET IT FOR FREE

Typemock (Commercial) vs. other frameworks.

The "free" products are not called free, they are open-source projects.
They are built in most cases by a single person, and maintained by the
community if they are successful.
There's a lot of effort and love put into that. What's the return? There's the
great satisfaction someone finds your software useful (Hey, that also goes
for commercial products).
Ayende, creator of Rhino Mocks and Daniel, creator of Moq, put a lot of
hours into feature requests and support, but there's a limit to what they
can do.
Take a look at Ayende's slogan on his blog: "Send me a patch for
this".
Don't be a whiner. Take responsibility. Compare the good, bad and ugly.
And pick what is right for you, not because it's what you can afford, but for
what it will save you, give you back or help you outperform your
competitors.
Of course you get what you pay for (Nothing + More nothing = Nothing).

TYPEMOCK

Established 2005, privately owned


Typemock Isolator
Thousands of customers (Fortune 500)
Tens of thousands licenses sold

TYPEMOCK.NET HISTORY

The Typemock Isolator product supports three sets


of API in order to fake dependencies:

Reflective Mocks

Natural Mocks

String based API (Oldest framework).


Record-Replay but strongly typed (Old framework).

Typemock Isolator

Arrange Act Assert (AAA) Syntax (Latest API version - you are encouraged
to use this).

ARRANGE ACT ASSERT (AAA)

The Arrange-act-assert pattern in the field of mock


frameworks represents us trying to return to basics.

Moq did that nicely by showing a way that leads there,


and it is being taken gladly by Rhino and Typemock
Isolator.

AAA is guidance because there was an outcry (a


silent, vote of feet) that record-replay is not cutting it
its too confusing for non-experts. Its too technical.
and it does not lend itself to the way people want to
work. So most people didnt use it.

the Twist

Typemock Isolator
Demo

Excuses

TOP FIVE EXCUSES FOR NOT UNIT TESTING


1.
2.
3.
4.
5.

I dont have time to unit test.


The client pays me to develop code, not write unit
test.
I am supporting a legacy application without unit
tests.
QA and User Acceptance Testing is far more
effective in finding bugs.
I dont know how to unit test, or I dont know how
to write good unit tests.

WHEN DO YOU THINK YOU'LL INTRODUCE


UNIT TESTING

A common answer to this question:

If you gave me this answer, I won't believe you.


Here's why:

"We're in a middle of a project right now. We'll wait two months until it
completes, then we'll have time".

If I came to you in two months and asked what has changed since last
time, you'll give me the same answer.

That's because development is always done under


pressure.

WHEN DO YOU THINK YOU'LL INTRODUCE


UNIT TESTING

In two months time, you'll be up to your neck in


fixing bugs, running away from QA reports. You'll fix
those bugs, and eat away at the time you thought
you'd have when the project completes. And when it
does complete (late), and you think it's over, you'll
start receiving bug reports from the customer. Guess
what? no time to start unit testing then either.
Let's face it, there is never a good time to start unittesting, or making any change, for that matter. So,
start today. Write your first unit tests. Change is
painful, and you'd rather delay that. But in agile, we
say: if it's painful, do it first.

TEST CODE IS JUST CODE - COMMON TRAPS

Some Anti-Patterns to avoid and some techniques for


making sure Test Code doesn't slow you down:

Cut & Paste

Poor Encapsulation

Isolation framework / Dependency Injection and Test Doubles

Too hard to write the Test

The builder and fluent interface patterns are very useful here

Bloated SetUp

Refactor test code

Refactor production code

Code Integration Test Pain

Remember Integration Testing as well

CLASSICISTS V MOCKIST V ISOLATOR

Classicists

The classical TDD style is to use real objects if possible and a double if it's
The Classicists does White-box Integration
awkward to use the real thing. So a classical TDDer would use a real
testing
warehouse and a double for the
mail service. The kind of double doesn't
really matter that much.
First generation TDD

Mockist

A mockist TDD practitioner, however, will always use a mock for any
The Mockist does White-box Unit testing
object with interesting behavior. In this case for both the warehouse and
the mail service.
Sencond generation TDD

Isolator and Fake

An isolator
TDD practitioner,
willdoes
alwaysBlack-box
isolate or fake
anytesting
object with
The
Isolator
and Fake
Unit
interesting behavior. In this case for both the warehouse and the mail
Third generation TDD
service.

INTRODUCING BDD

Behaviour-Driven Development (BDD)

Test method names should be sentences


A simple sentence template keeps test methods focused

By Dan North
BDD is another variation on TDD that tends to use mockist testing

This sentence template The class should do something means you can only
define a test for the current class. This keeps you focused. If you find yourself
writing a test whose name doesnt fit this template, it suggests the behaviour
may belong elsewhere.

An expressive test name is helpful when a test fails

Behaviour is a more useful word than test.


Determine the next most important behaviour.
Requirements are behaviour, too.
BDD provides a ubiquitous language for analysis.
Acceptance criteria should be executable.

WHEN TO USE TDD/BDD

When you have to implement a new functional


requirement, or make a requirement up yourself.

Note: When you want to change existing code, first


write covering Unit Tests (white box testing).
Then use TDD to add new functionality.

TOOLS YOU NEED TO KNOW ABOUT


Continuous Integration
Build Automation Tools
MSBuild
Nant
FinalBuilder
CI Servers
Team System / Team Foundation Server
TeamCity (R#)
CCnet (CruiseControl.NET)
FinalBuilder Server

TOOLS YOU NEED TO KNOW ABOUT


Visual Studio Integration
Refactoring
R# (ReSharper)
Code Rush

TOOLS YOU NEED TO KNOW ABOUT


Isolation / Mocking Frameworks for .net
Open Source
Rhino Mocks for .NET
NMock for .NET
Moq for .Net
Commercial (costs money but worth it)
Typemock Isolator
Typemock Isolator For SharePoint

Where to go from here

WHERE TO GO FROM HERE

You dont have to start big


Start new tasks with TDD
Add Tests to code that you need to change or
maintain but only to small parts
Proof of concept
If it's worth building, it's worth testing.
If it's not worth testing,
why are you wasting your time working on
it?

LINKS

Books

Blog

http://www.typemock.com/

Unit testing Silverlight:

http://research.microsoft.com/en-us/projects/esm/nagappan_tdd.pdf

Typemock

The Typemock Insider Blog (http://blog.typemock.com/)

Unit test study from Microsoft Research:

Test-Driven Development in Microsoft .NET (http://www.amazon.co.uk/gp/product/0735619484)


Test-Driven Development by Kent Beck (C++) (http://www.amazon.co.uk/gp/product/0321146530)

http://www.codeplex.com/CThru

Other links:

http://en.wikipedia.org/wiki/Test-driven_development
http://www.testdriven.com/
http://www.mockobjects.com/ - Online TDD book: http://www.mockobjects.com/book/index.html
http://www.martinfowler.com/articles/mocksArentStubs.html
http://dannorth.net/introducing-bdd
http://behaviour-driven.org/Introduction

Q&A

Vous aimerez peut-être aussi