TDD Hello, World
Code for this post can be found here
I was recently looking at a video about clean code
and realized I’ve never tried this thecnique of software development before, despite the fact of having years of experience, at one point, that was also the case for the speaker in the video at the time he fisrt tryed Test Driven Development, so this post aims to document my first steps into this world.
You’ll need some basic knowledge of python
and git
Here’s an old good friend Hello World
written in python
:
print("Hello World")
Let’s start
Let’s create our project structure or simply clone the repo above:
mkdir -p ~/dev/tdd-hello_world/src
cd ~/dev/tdd-hello_world/src
echo "print(\"Hello World\")" > hello.py
You can run this code with python hello.py
and the output will be Hello World
.
Make it testable
Now we have to refactor this code to make it more testable which means separate our domain code from the outside world, in this case, our domain is just a string of text, refactored code will be:
def hello() -> str:
"""Return a greeting"""
return "Hello World"
print(hello())
Hello test
Now we’re ready to start writing our first test, create a file called hello_test.py
next to our hello.py
file.
from hello import hello
def test_hello():
want = "Hello World"
got = hello()
assert want == got
pytest
, if you don’t have it installed do pip install pytest
, it should show the test passed, try changing the want
string and running pytest
again to check if it fails.
Rules for writing tests
There are a couple conventions we must follow when writing a test, it is basically like writing a function with the following conditions:
- The name of the file must be
xxx_test.py
ortest_xxx.py
, wherexxx
is the name of the file with our business logic code. - The function inside that file must start with
test
.
Change of requirement
Now, the user has a new idea, what about if we know the name of the user we’re greeting? He wants to get a customized greeting message! First, we change our test to reflect that new requirement:
from hello import hello
def test_hello():
want = "Hello, Douglas!"
got = hello("Douglas")
assert want == got
pytest
now, it fails!
def test_hello():
want = "Hello, Douglas!"
> got = hello("Douglas")
> E TypeError: hello() takes 0 positional arguments but 1 was given
def hello(name: str) -> str:
"""Return a greeting"""
return f"Hello, {name}!"
def test_hello_without_name():
want = "Hello, World!"
got = hello()
assert want == got
def test_hello_with_name():
want = "Hello, Douglas!"
got = hello("Douglas")
assert want == got
def hello(name: str = None) -> str:
"""Return a greeting with and without name"""
if not name:
name = "World"
return f"Hello, {name}!"
pytest -v
will get the following result:
=============================== test session starts ================================
platform darwin -- Python 3.9.7, pytest-7.0.1, pluggy-1.0.0 -- /.../bin/python3.9
cachedir: .pytest_cache
rootdir: ~/dev/tdd-hello_world/src
collected 2 items
hello_test.py::test_hello_without_name PASSED [ 50%]
hello_test.py::test_hello_with_name PASSED [100%]
================================ 2 passed in 0.01s =================================
Keep the process simple with 3 key steps
- Always start by writing a failing test and make sure it fails!
- Write the minimum amount of code to pass the test, this way we are certain of having a working version of the software! And,
- Refactor the code to make it secure, readable, fast, and easy to maintain.
From here, we can continue working on new requirements like adding translations or new user’s ideas.
Thanks for dropping by!