@gianchub
Skillsmatter - London
October 21th, 2015
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.
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?
It all happened when I moved to 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 Beckowl
Robert Martinowl
TDD strooong
in them was...
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(**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)
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)
def very_long_function(*args, **kwargs):
# nasty piece of code that does
# a lot of things.
return result
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
gianchub
gianchub
gianchub [at] gmail [dot] com