One of the things that I have observed both in my own practice of software development, and from what I can see of others is that the concepts of Test Driven Development (TDD) are so counter intuitive and it takes considerable self-discipline, self-restraint and self-awareness to ensure that tests are constructed before code is written. So what does it take to overcome this barrier?
I suspect part of the problem is in the way that software development is taught. I totally understand that it makes sense to focus on the immediate gratification of “Look! See what you can do!”. The problem is that this idea becomes so ingrained and instinctive that software developers are naturally oriented towards “I can just fix this”, or “this needs to be tweaked” as opposed to “how do I test the correctness of the changes I want to make?”
I wonder if part of the problem is the ubiquitous “Hello World”. Yes, it’s a simple and obvious implementation to show that you have successfully implemented something in your language of choice, but there are (usually) no tests. So this got me thinking, what would a unit or integration tested Hello World look like?
Here’s my attempt at a test-driven “Hello World” application implemented in Python3. Keep in mind that this is not me saying “I got the answer!”, but more an exploration of “what if?” to see if some of relevant issues can be uncovered.
What’s the problem?
Of course, in TDD we would write a test before we implemented any code, but for the purpose of this post, we are deconstructing an existing implementation of a “Hello World” application for pedagogical purposes. We want to understand what concepts it is necessary to understand to be able to implement a TDD style “Hello World” application. So here’s an example application in Python.
# hello_world.py def my_main_function(): print('Hello World') if __name__ == "__main__": my_main_function()
We have a single function with no arguments
my_main_function that calls a
statement is Python boilerplate to ensure that the function is called when run
from the command line using a command such as
From a TDD perspective we need to be able to detect that the text emitted to the
console is “Hello World”, or perhaps simply that the
stdout, how it
relates to the print functions and thus mock
stdout as an indirect way of
acquiring the result of “Hello World”. Complicated? Yeah, seems so, for a
But let’s keep exploring this idea and see where it leads…
Python TDD Hello world
For the Python implementation I’m using the
pytest unit test framework, along
pytest_mock package for mocking. You could just as easily implement
the concept using the
unittest framework with the usual caveats regarding the
additional boilerplate that people are usually trying to avoid by using pytest,
although it would have the advantage that
unittest and its mocking capability
is in the standard Python library and does not require any additional
In Python, tests are conventionally implemented in separate files from the code it is testing. In trying maintain the spirit of a “first testable application” I’m going to implement the test in the same file as the application.
# hello_world.py import io def my_main_function(): print('Hello World') def test_hello_world(mocker): # `print` appends a newline character that we have to allow for in the test. EXPECTED_VALUE = 'Hello World\n' mock_stdout = mocker.patch('sys.stdout', new_callable=io.StringIO) my_main_function() assert mock_stdout.getvalue() == EXPECTED_VALUE if __name__ == "__main__": my_main_function()
Now you can run the test using the command
pytest hello_world.py on the
command line, or as before, run the application using
At least in Python, a test driven “Hello World” application is clearly possible. Unfortunately there are a number of extra concepts that must be understood that may represent a barrier to a learner; mocking, test frameworks and additional build dependencies and execution commands. Also, when extending this to statically typed languages such as Rust, C or C++, it becomes much less clear how the concepts of mocking could be applied (admittedly perhaps due to my own inexperience with mocking in those languages).
Interesting though, no?