Intro
Let’s dive into the world of Test Driven Development (TDD) together, shall we? π
So, what exactly is TDD? Well, it’s a way to describe things in a programming language.. Imagine it’s like telling a story, but instead of using words, we’re using code!
Here’s how it works: when we want to describe something using English, we focus on describing one thing at a time.
It’s like building with Lego bricks – we start with one piece and add more as we go along!
But here’s the cool part: just like in science like physics, we can even test our code, to see if it behaves the way we expect it to. It’s all about making sure our code is usable and understandable, just like in a science experiment!
So, think of TDD as our own little computer-science experiment. We write down our specifications and then make sure the computer behaves the way we want it to π€β¨
Music Intro
Lets do some coding!
First we split our code into 3 parts: “given”, “when”, and “then”
# Given (where we set our preconditions)
number1 = 1
number2 = 2
# When (where the action happens)
result = number1 + number2
# Then (where we assert/return our output)
print(result)
π» CodeWith the print in the end, we can verify the result manually:
Python3 2024-06-03 on Linux x86_64)
----
3
π» Terminal resultYou can always use our web editors: π» Python / π» JavaScript / π» Groovy / π» C#
The “given”, “when”, and “then” is usually known in TDD as the triple A’s: “Arrange”, “Act”, and “Assert” and they do the same, except given, when, then is easier to read and arrange, act, assert is more technical.’
# Given two numbers are defined
# When the numbers are added together into the result
# Then the result must be verified to be the sum
# Arrange: two numbers are defined
# Act: the numbers are added together to get the result
# Assert: verify the result is the sum of the numbers
π» CodeAssert instead of print
What we can do instead, is to assert it automatically, by replacing print with assert:
# Given
number1 = 1
number2 = 2
# When
result = number1 + number2
# Then
assert(result == 3)
π» CodeThe == means that we want the computer to verify if the equal is actually equal.
It responds with either true (the equal is equal) or false (the equal is not equal).
The assert consumes the true or false and if it’s true, then it does nothing, because everything is fine:
Python3 2024-06-03 on Linux x86_64)
----
π» Terminal resultIf it’s true, then it the codes passes and everything is fine (even though we can’t see it, but no news is good news!).
Assert & print
If we want a result we can print it:
# Given
number1 = 1
number2 = 2
# When
result = number1 + number2
# Then
print(f"result: {result}")
assert(result == 3)
π» CodeThe f in the f”…” means it is a text with parameters, where we can take the value of result.
It has different names in different programming languages:
Language | Example | Name |
Python | f"text {parameter] text" | f-string |
JavaScript | `text ${parameter} text` | template string |
C# | $"text {parameter} text" | interpolated string |
Groovy | "text {parameter} text" | g-string |
Negative test
To see a negative result, we need to replace the 3 with a 4 (because 1+2 is not 4):
# Given
number1 = 1
number2 = 2
# When
result = number1 + number2
# Then
assert(result == 4)
π» CodeThen we will see an assertion error, where the result is not 4:
Python3 2024-06-03 on Linux x86_64)
----
Traceback (most recent call last):
File "apps/console-python/", line 9, in <module>
assert(result == 4)
AssertionError
π» Terminal resultBetter error messages
To give it a better error message, we could add an actual error message:
# Given
number1 = 1
number2 = 2
# When
result = number1 + number2
# Then
assert(result == 4), f"(actual) {result} != 4 (expected)"
π» CodeWhich gives:
Python3 2024-06-03 on Linux x86_64)
----
Traceback (most recent call last):
File "apps/console-python/", line 9, in <module>
assert(result == 4), f"(actual) {result} != 4 (expected)"
AssertionError: (actual) 3 != 4 (expected)
π» Terminal resultand put it inside the text. So, f”{result} =! 4″ becomes: “3 != 4”
You can see, some languages are more fun than others π
Why use an assert, when print makes it much easier?
In a simple program like that, we can use a print.
A more complex program may have 20 kinds of outputs, depending on the inputs.
It is much easier, faster and more precise to automate all the outputs, instead of testing them manually:
# Imagine we have already a complex program called buyTicket(numberOfZones, travelerType)
# here would the tests be:
assert (buyTicket(1, "adult")=="2 β¬")
assert (buyTicket(8, "adult")=="16 β¬")
assert (buyTicket(1, "child")=="1 β¬")
assert (buyTicket(8, "child")=="8 β¬")
# etc...
π» CodeNo need to run the buyTicket manually 20 times and checking all the values are correct.
A machine can run a 1000 test cases per minute, and we humans can’t.
And there is also no need to remember all the results, when the machine can do it for us.
Testing before coding
TDD is not only about testing the code.
It’s more about writing down our assumptions that we have in our head.
It’s about getting your idea out of your head and define where we start and where we need to end.
So, often we need to start with the given’s (where we start) and the then’s (where we need to end):
# Given
# write your code before writing the when code
# When
# write your code after writing the given and then code
# Then
# write your code before writing the when code
π» CodeThe when code is written last, for the given and then are the specification of the wanted system behavior. The when code is the required logic that makes the given and then to connect.
And whenever we want to change the specification, we just need to change the given and the then code. Then we will see the existing when code will fail, and therefore needs to be refactored (updated).
Exercise:
Write the needed when code, so all the asserts pass. Please don’t change the code in the given and then.
# Given (writen before when)
number1 = 1
number2 = 2
number3 = 3
number4 = 5
# When (written after given and then)
# your code goes here
# Then (written before when)
assert(result1 == 3), f"{result} =! 3"
assert(result2 == 4), f"{result} =! 4"
assert(result3 == 5), f"{result} =! 5"
assert(result4 == 6), f"{result} =! 6"
assert(result5 == 7), f"{result} =! 7"
assert(result6 == 8), f"{result} =! 8"
π» CodeHint or Check if your result is correct)
# Given
number1 = 1
number2 = 2
number3 = 3
number4 = 5
# When we add 2 numbers together to get the result1-6
result1 = number1 + number2
result2 = number1 + number3
result3 = number2 + number3
result4 = number1 + number4
result5 = number2 + number4
result6 = number3 + number4
# Then
assert(result1 == 3), f"{result} =! 3"
assert(result2 == 4), f"{result} =! 4"
assert(result3 == 5), f"{result} =! 5"
assert(result4 == 6), f"{result} =! 6"
assert(result5 == 7), f"{result} =! 7"
assert(result6 == 8), f"{result} =! 8"
What’s next?
In the next lessons, we will do some coding exercises.
I would like you to use the assert, so you don’t have to remember the results from all the exercises.
You are welcome to add a print, if you want to. It can be very useful, to use a print, get a view inside to see what the code is doing.
Saving and loading
In the web editor (in case you want to use that to begin with), there is no option to save your code, but what you can do is to copy & paste your code into a notepad for future use.
Then you can always copy & paste it back into a web editor, if you want to use it again.
It is also possible to have multiple web editors open, without them interfering with each other.
Exercise:
Add an assert after the print. And make sure the whole code passes.
# Given name and a greeting is defined (you can use any name)
name = "Bartek"
greeting = "Hello"
#When the greeting, a space, and the name is combined into the text.
text = greeting + " " + name
# Then the text can be printed as output and be verified by us
print(text)
π» CodeHint or Check if your result is correct)
assert(text == “Hello Bartek”)
Then save your code into your favorite notepad, and save it.
Then update the code, to make it fail with an AssertionError.
Extra: if you want more challenge, you can try to add an improved error message.
Spilting:
Sometimes it is not possible to write code in the given, when, then format.
This is a sign, that we should split the code into smaller parts (like methods/functions or classes).
A piece of code should often only do a single thing, even though the outputs can be different.
Conclusion
Let’s wrap up our journey into Test-Driven Development (TDD), shall we? π
So, here’s the scoop: Test-Driven Development (TDD) offers a structured approach akin to the scientific method, providing a framework for software development that prioritizes clarity, predictability, and reliability.
Picture this: before we even start writing the actual code, we write tests to describe how we want our software to behave. It’s like drawing a map before going on a big adventure – it helps us know where we’re going!
And here’s where things get really cool: we use something called assertions to check if our code works the way we want it to. It’s like having a super fast and precise robot double-checking our work to make sure everything’s OK! π€β
TDD not only makes testing super fast and easy, but it also helps us understand our coding problems better. It’s like putting together a puzzle – each piece fits together perfectly to create something awesome!
So, as we dive deeper into coding and keep exploring TDD, let’s make assertions our best friend. They’ll help us build super strong, super reliable software that can handle anything life throws our way! πͺπ