TDD is not JUST
about tests
Fabrizio Romano
@gianchub
Skillsmatter - London
October 21th, 2015
Hello London!
Thank you for being here!
I'm a Computer Science Engineer, addicted to Python, clean code and books.
I'm also writing my own, it's going to be out in Jan. 2016.
About me
The plan:
What drew me to TDD?
Why do we need it?
A story about TDD
...and let's have some fun while we do it, ok?
A little disclaimer
- This is my own view
- Simple examples
- No definitions
What drew me to TDD?
It all happened when I moved to London...
Mark Henwood
Don't worry,
TDD will take us there
Ondrej Kohout
Too much logic!
If someone is
achieving great results:
Observe and learn
Why do we need TDD?
def is_positive(n):
# We assume n is integer.
return n > 0
Example #1
How do we test this function?
Boundaries
def is_positive(n):
# We assume n is integer.
return n > 0
eq(False, is_positive(0))
eq(False, is_positive(-3))
eq(True, is_positive(3))
Is this a good test?
def is_positive(n):
# We assume n is integer.
return n > 1
eq(False, is_positive(0)) # still passing
eq(False, is_positive(-3)) # still passing
eq(True, is_positive(3)) # still passing
Granularity
def is_positive(n):
# We assume n is integer.
return n > 1
eq(False, is_positive(0)) # still passing
eq(False, is_positive(-1)) # still passing
eq(True, is_positive(1)) # NOW FAILS!
Much better!
The boundary cannot jiggle any more!
def is_positive(n):
# We assume n is integer.
return n > 0
eq(False, is_positive(0))
for n in range(1, 10 ** 4):
eq(False, is_positive(-n))
eq(True, is_positive(n))
Even better!
But unit tests need to be FAST...
So, can we test everything?
def is_positive(n):
# We assume n is integer.
if n == 10 ** 16:
return 'Hola!'
return n > 0
If you could test 1'000'000'000 numbers a second, it would take about 4 months to spot this.
We cannot test everything.
def get_squares(v):
# assumes v is a list of integers
if not v:
return []
return [n ** 2 for n in v]
Example #2
How do we test this function?
def get_squares(v):
# assumes v is a list of integers
if not v:
return []
return [n ** 2 for n in v]
eq([1, 0, 4, 9], get_squares([-1, 0, 2, -3]))
eq([], get_squares([]))
But what about that redundancy?
We may not notice it, if we tested AFTERWARDS
def get_squares(v):
# assumes v is a list of integers
if not v:
return []
return [n ** 2 for n in v]
def get_squares2(v):
# assumes v is a list of integers
return [n ** 2 for n in v]
# this would cause us to write get_squares2
eq([1, 0, 4, 9], get_squares2([-1, 0, 2, -3]))
# this would automatically pass, thanks to
# the list comprehension
eq([], get_squares2([]))
Had we written the tests first, there would be no redundancy.
Better than solving these problems, is to avoid introducing them in the first place.
And that's where TDD comes into the game
So let's hear a story about TDD
Psst: It's extremely technical, beware!
Once Upon a Time...
there was a frog
He was in love with a beautiful princess. One day, at the pond, the frog took courage, jumped out of the water and told her:
I am a prince under a spell, kiss me,
break the spell and marry me!
Prince? Intriguing!
But she was a Geek...
TDD?
Let me get back
to you on this...
And he ran off to learn TDD from the masters...
Kent Beckowl
Robert Martinowl
TDD strooong
in them was...
TDD
Test Driven Development
TDD is a Software Development Process based on the repetition of a very short development cycle.
Def:
Steps
- Short at first
- With experience: longer
- Trouble? Go back to short
Where does it start?
The frog thought the training was completed
But the masters disagreed,
and they kept giving examples...
What changes?
Without TDD
What & How
With TDD
What
How
OMG! It's like
having 2 brains!
TDD common aspects
- KISS
- YAGNI
- Architecture design during refactoring
- Three strikes and refactor
(Test-Driven Development with Python - H. Percival) - Triangulation
?
Triangulation
eq(4, square(-2))
def square(n):
# we can cheat, it is
# the only requirement
return 4
First step
"Fake it 'till you make it"
eq(4, square(-2))
eq(9, square(3))
def square(n):
return n ** 2
With Triangulation
You write
the actual logic.
Main Benefits
- Refactor with Confidence
- Readability
- Loose Coupling
- Easier to test and maintain
- Test first => Better understanding of requirements
- Small units => easier debugging and tests as docs
- Higher speed:
It takes less to write tests and code
than to write code and debug
Main Shortcomings
- Whole company needs to believe
- Blind spots
- Badly written tests are hard to maintain
Real life examples
How do you test legacy code?
Better way...
Changing a horribly long view
def get(request, *args, **kwargs):
# imagine many lines of code here...
data = get_data(**search_params)
# here data is prepared, worked on
# put in the context dictionary
# and the view finally renders
# a template
return render(template_name, context, extra_params)
We need to insert pagination, filtering, sorting
def get(request, *args, **kwargs):
# same as before
original_data = get_data(**search_params)
filtered_data = filter_data(
original_data, **filter_params)
sorted_data = sort_data(
filtered_data, **sort_params)
data = paginate_data(
sorted_data, **pagination_params)
# same as before
return render(template_name, context, extra_params)
We code pagination, filtering and sorting with TDD
Introducing a new functionality in existing code
We need to add a feature to a long piece of untested code.
def very_long_function(*args, **kwargs):
# nasty piece of code that does
# a lot of things.
return result
We cannot test it (no time, badly written, etc.)
One possible solution:
def test_new_functionality():
# preparation stage
result = very_long_function(*args, **kwargs)
eq(expected_result, result)
def very_long_function(*args, **kwargs):
# same nasty piece of code
# with NEW FUNCTIONALITY IN
return result
After all these examples,
the frog was in ZEN-Mode
He went back to the princess and passed the exam.
So they married, and when the minister said:
"You can kiss the bride"...
Nothing changed!
He was just a talking frog after all!
What's the moral of the story?
The princess should have tested FIRST!
And so should you
Thank you! Come say hi!
gianchub
gianchub
gianchub [at] gmail [dot] com
TDD is not just about tests (SM London)
By Fabrizio Romano
TDD is not just about tests (SM London)
Skillsmatter talk: TDD is not just about tests.
- 2,171