@gianchub
EuroPython 2015 - Bilbao
July 21th
0110010101100110
Got it?
Hello! (Amazing joke about the bit...)
The plan (we're here)
What drew me to TDD?
Why do we need it?
A story about TDD
It all happened in London...
Don't worry,
TDD will take us there
Too much logic!
def is_positive(n):
# We assume n is integer.
return n > 0
How do we test this function?
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
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...
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.
def get_squares(v):
# assumes v is a list of integers
if not v:
return []
return [n ** 2 for n in v]
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.
Psst: It's extremely technical, beware!
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!
TDD?
Let me get back
to you on this...
Kent Becko
Robert Martiño
TDD was strooong in them...
TDD is a Software Development Process based on the repetition of a very short development cycle.
Def:
OMG! It's like
having 2 brains!
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.
def get(request, *args, **kwargs):
# ...
# imagine many lines of code here...
# ...
data = get_data(**params)
# ...
# data is prepared, worked on
# put in the context dictionary
# and the view finally renders
# a template
return render(template_name, context, extra_params)
def get(request, *args, **kwargs):
# same as before
original_data = get_data(**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)
def very_long_function(*args, **kwargs):
# nasty piece of code that does
# a lot of things.
# Uncle Bob would cry if he saw it...
return result
def test_new_functionality():
# preparation stage
# ...
result = very_long_function(*args, **kwargs)
assert_equal(expected_result, result)
def very_long_function(*args, **kwargs):
# same nasty piece of code
# with NEW FUNCTIONALITY IN
# Uncle Bob still unhappy
return result
gianchub
gianchub
gianchub [at] gmail [dot] com
http://slides.com/gianchub/ep2015-tdd