Upload
brian-rasmussen
View
6.662
Download
0
Embed Size (px)
DESCRIPTION
These are my slides for a TDD presentation on 2009-04-29
Citation preview
TEST-DRIVEN DEVELOPMENTPresenting TDD
2009-04-29
Brian Rasmussenhttp://www.linkedin.com/in/brianrasmussen
AGENDA
Answers to the WH-words (WHO – WHAT – WHERE)
Where to begin
The Turn …
… the Twist
Excuses and Common Traps
Where to go from here
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 Code that fulfills requirements
Write Functional Code 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 No code without a failing test
Make it Work As simply as possible
Make it Better Refactor
TDD CYCLE
New require-ment
Write new test
Run tests
Write new codeRun tests
Refactor
Run tests
Make it Fail
Make it Work
Make it Better
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
Requirements Coding Integration Testing Support0%
20%
40%
60%
80%
100%
0
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000
% of Defects Introduced Cost to Fix a Defect
% d
efec
ts c
reat
ed
Thou
sand
$s
The pain is here! This is too late…
MS:
VS
MS:
MSN
MS:
Windows
IBM: D
rivers
0%
20%
40%
60%
80%
100%
120%
140%
160%
Time To Code FeatureTime To Code Feature us-ing TDDDefect density of teamDefect density of team us-ing TDD
IS TDD A WASTE OF TIME (MICROSOFT RESEARCH)
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, …
Test types: Black-box test White-box test
The only tests relevant to TDD is Black-box Unit Testing
DIFFICULT SCENARIOS TO UNIT TEST
Closed Object Models (Sharepoint, Silverlight) Client – server architecture
Communicating Across a Network
An out-of-process call Includes talking to databases and Web Services.
UI 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…?
CB
DE
A
HOW TO DO TDD
… on my component A?
If my component reference… My coworkers component A third party component A very slow component (Database, Web service) A component with complex set up A component with exceptional behavior (Exception) A remote component (Remoting) Circular dependency
Do I have to wait on these components to be created and/or tested?
This, and the previous two slides,are all thoughts on implementing tests on existing code.
This is all White-box Unit- or Integration Testing and has therefore nothing to do with TDD.
In TDD you write a Black-box Unit test that fails, first,and worry about the code implementation later.
SINGLE MOST IMPORTANT THINGWHEN LEARNING TDD
Do notwrite the code in your
headbefore 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 DON’T 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 andTest Doubles (Mock Objects)
Or (the new way)“Isolate” and “Fake”
Using Typemock Isolatorand AAA - The "Arrange-act-assert" pattern
WHY “ISOLATE” AND / OR “FAKE” AT ALL
… when you can hand-write mocks yourself.
ASP.NET MVC example
WHY “ISOLATE” AND / OR “FAKE” AT ALL
… when you can hand-write mocks yourself.
ASP.NET MVC AccountControllerTest file contains 25 tests. The mocking code starts at line 376 and goes on until line 668 (the end
of the file). That's 293 lines of mocking code, some of it contains logic.
Rewriting all this with Isolator code 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.
It's a waste of time.Start using an isolation framework now.
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 String based API (Oldest framework).
Natural Mocks 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 – it’s too confusing for non-experts. It’s too technical. and it does not lend itself to the way people want to work. So most people didn’t use it.
… the Twist
Typemock Isolator Demo
Excuses
TOP FIVE EXCUSES FOR NOT UNIT TESTING
1. I don’t have time to unit test.2. The client pays me to develop code, not write unit
test.3. I am supporting a legacy application without unit
tests.4. QA and User Acceptance Testing is far more
effective in finding bugs.5. I don’t know how to unit test, or I don’t know how
to write good unit tests.
WHEN DO YOU THINK YOU'LL INTRODUCE UNIT TESTING
A common answer to this question: "We're in a middle of a project right now. We'll wait two months until it
completes, then we'll have time".
If you gave me this answer, I won't believe you. Here's why:
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 unit-testing, 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 Refactor test code
Poor Encapsulation The builder and fluent interface patterns are very useful here
Bloated SetUp Isolation framework / Dependency Injection and Test Doubles
Too hard to write the Test 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 awkward to use the real thing. So a classical TDDer would use a real warehouse and a double for the mail service. The kind of double doesn't really matter that much.
Mockist A mockist TDD practitioner, however, will always use a mock for any
object with interesting behavior. In this case for both the warehouse and the mail service.
Isolator and Fake An isolator TDD practitioner, will always “isolate” or “fake” any object
with interesting behavior. In this case for both the warehouse and the mail service.
The Classicists does White-box Integration testingFirst generation TDD
The Mockist does White-box Unit testingSencond generation TDD
The Isolator and Fake does Black-box Unit testingThird generation TDD
INTRODUCING BDD
Behaviour-Driven Development (BDD) By Dan North BDD is another variation on TDD that tends to use mockist testing
Test method names should be sentences A simple sentence template keeps test methods
focused 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 doesn’t 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 IntegrationRefactoring 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 don’t 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 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)
Blog The Typemock Insider Blog (http://blog.typemock.com/)
Unit test study from Microsoft Research: http://research.microsoft.com/en-us/projects/esm/nagappan_tdd.pdf
Typemock http://www.typemock.com/
Unit testing Silverlight: 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