Hello World in Python: TDD Approach

Most of the time we write our code then check them by ourselves. We test our codes for their expected behavior. When the project is small this might work, but when things gets bigger, our fear gets bigger. We become afraid that we might miss some tests, our we might lose our attention for during longer testing session.

That’s why we use TDD. In short, besides writing the codes for functions, feature we write some additional codes that tests the functional codes! And always write the tests first. Thus no matter what size the project is, testing becomes faster, error detection becomes faster, and end of the day we feel confident that the everything works. Even then we can refactor our codes easily because if something breaks, we can get instant feedback where we messed thing up.

Let’s say, we are going to write a function. That function has some input and output right? Now we’ll write the test first. In the test, we’ll call the function and see if it returns the expected. At first in a directory create two files mycodes.py and mytests.py . Our actual codes will be inside mycodes.py file, and we will write our tests in mytests.py. Now following TDD convention, we’ll write our test first in mytests.py. Basic structure for writing tests are as follows:

First import unittest module, then import our codes, then declare a class inheriting TestCase class of unittest. Then inside this class we’ll write our tests as methods. If this feels overwhelming now, just remember the structure, for start all you need to do is modify the methods in the class.

Suppose, our function name is hello, it will take a name as parameter, then show a greeting. When you give the function a name ‘John’, it will give ‘Happy testing! John’, if the name is ‘Jane’, the output will be ‘Happy testing! Jane’. The function is pretty simple but we’ll write the test case first. After writing the test, our mytest.py we’ll look like:

After you run this mytests.py file, you’ll see some output like this:

Yes, lots of info, but just the last line is important for use now. Which says Failed(errors=1). Inside the test_hello method we have written:

self.assertEqual(hello('John'), 'Happy testing! John')

In short, this line is testing the output of hello(‘John’) is equal to ‘Happy testing! John’ . And clearly it’s failing. Because there is no function named hello anywhere!. And this clue is already in the output, can you find it?

Now let’s fix this failing test step by step. We’ll follow baby steps. First, open mycodes.py and then define a function:

If you run tests after adding this line you’ll see it’s still failing, but there is also a valuable information why its failing:

TypeError: hello() takes 0 positional arguments but 1 was given

You can see this line in the output right? It’s saying that the function hello() you wrote doesn’t takes any argument, but in the test you are trying to pass one. It’s true indeed. Let’s give the function a parameter:

Now run the code. It says:

AssertionError: None != 'Happy testing! John'

It means that the function is returning None which is not equal to the return value we are expecting. Now make the function return our desired string:

Check the output, it’s still failing, why?

AssertionError: (‘Happy testing! ‘, ‘John’) != ‘Happy testing! John’

Hmm, though our tester is receiving the data, but not in the format it’s expected. To fix this:

Now run the test, and the output is:

That means our code has passed all the test. If we want to test this function for another name, we can write another method or just add another assertEqual method in the existing test.

In our test we used assertEqual method. There are many cases where you don’t want to test just equal, may be you may want to test if the return is of certain type, or certain thing is inside the returning list and many more. Here I give you a list of widely used unit test methods:

assert: base assert allowing you to write your own assertions
assertEqual(a, b): check a and b are equal
assertNotEqual(a, b): check a and b are not equal
assertIn(a, b): check that a is in the item b
assertNotIn(a, b): check that a is not in the item b
assertFalse(a): check that the value of a is False
assertTrue(a): check the value of a is True
assertIsInstance(a, TYPE): check that a is of type “TYPE”
assertRaises(ERROR, a, args): check that when a is called with args that it raises ERROR

After this I hope you understand the general workflow of TDD. But for your clarity here i give you again:

Source: centricconsulting.com

Started(writing) with poetry, ended up with codes. Have a university degree on Biotechnology. Works and talks about Java, Python, JS. Have philophobia.