PPL 2021 — Introduction to Test-Driven Development

I don’t always test my code. But when I do, it’s in production

Photo by James Harrison on Unsplash

This article is made as a part of Individual Review of PPL 2021.

Introduction to Test-Driven Development

As software developers, we may (or may not) have heard about this software methodology. Software testing is not a new method. It’s been invented in the ’90s. As the program gets more complex and has so many features, it’s easier for the program to break down in a production state. When that happens, every developer meets with a headache as a bit of change in one function can alter the whole program and need so many adjustments. This thing makes the software unreliable. Also, fixing a bug in the production has so many cost and even can make the user can’t use the whole program.

That’s why in 1998, one of the article about extreme programming mention, “we usually write the test first”, and from there, Test-Driven Development starts to grow. Until finally, in 2003, Kent Beck releases a publication, “Test-Driven Development: By Example.”

Test-Driven Development Principle

Without Test-Driven Development, usually, the developer will implement the features first and then check to see if there is any bug. This way, as I mentioned before, every change that was made after the feature is complete will have the probability to break the entire code.

With Test-Driven Development, as the name suggests, it is mandatory to write the test for specific features first and then write the implementation code later. TDD has a unique three unique steps, and that is “Red-Green-Green”. What this means is that every developer should write the first and then run the test. For the first run, the test must fail, as there is no implementation code for it. After that, developers can start to write the implementation code. For this step, our primary goal is to ensure that the test will pass, so the cost (such as complexity or memory usage) is not substantial in this step. The last step is a refractor. In this step, our previous code must be optimised and, if there are any unusual naming or unused variables, it can be deleted to make the code more memory-friendly.

So, in short, the basic principle of Test-Driven Development is to make the test -> make the code to pass the test -> optimised the code.

Test-Driven Development Illustration

First Step: Red

It may sound ridiculous at first, but the first step to Test-Driven development is writing the test and making sure that it fails. That’s why this stage is called ‘RED’. Because the pipeline will turn red when the test is not passed. Some points were encouraged in this step, and that step is :

  • Write small — It is essential to write your test one features or function at a time. This way, the implementation code won’t be too complicated, and if there’s any error, you can detect it immediately.
  • Cover any possibilities — Say that your code should have three expected output. The best practice is to take the test for those three scenarios as well. So that you can be sure that your code will be work as you intended.
  • Don’t overdo it — Even though you are encouraged to test every possible output of your code, it is best if you don’t test any trivial codes. Too many tests for trivial code will make the test unreliable to the core function of your code.

Second Step: Green

After we take our first test, the next step would be to pass that test. In this second step, the essential point is that you have to pass that test, so anything about program cost, complexity, and anything else is not mattered. This is also to speed up the development process, and sometimes the best idea for the program algorithm can’t come naturally.

You need to note that you have to pass the test and ensure that your implementation won’t make the test unusable. This is why practice is your best friend. The more we practice writing the test first, then the implementation will ensure that we can make a good test and ensure the implementation code won’t violate our unit test.

Final Step: Refactor

We have written our test, we have implemented it, now it’s time for optimisation. As I said earlier that in the second step, the goal is to pass the test. Complexity or cost doesn't matter. In the final step, it’s time to refine our code or, in other words, refractor.

In this step, we can look for unused variables, faster algorithm or renaming our variable so that our code is readable and easier to maintain in the future. We always need to remember that our refractor code should never add a new feature or omit an existing one. This way, when we have done with the refractor, the test is still reliable.

Benefits and characteristics projects that implement Test-Driven Development

We’ve known what Test-Driven Development is, the implementation, and now, of course, we’re asking the benefits of Test-Driven Development. Benefits of Test-Driven Development :

  • Because we write the test first, this makes our program have a significant decrease in defect rates. Even though the cost of project initiation is higher, it is better to detect any bug in the development stage than in the production stage.
  • Test-Driven Development also said to increase code qualities, whether it’s about complexity or clean code. Because after every implementation, the developer will review their code and make a refractor.

The main benefits of Test-Driven Development are a significant decrease in defect rates and better bug detection in the development stage.

Example of Test-Driven Development

After we know how much the benefits of TDD. I will show you the example of the test code and the code that I test for my PPL course. For a little information, my project is a web app that will bridge farmers and buyer. My app also can give farmers some insight article and farmers can ask directly to the professional staff available.

Below is my test code for the signup (in this case the user is a farmer) and login function to the system. The basic idea of testing a program is you have to test the program output, is it correct the way you want it or is there any program detected by the test?

A brief explanation for the code above, the setUp section contain database information for our test. In this example, the setUp creates a new user and save it (the user data is then destroyed after the test is completed). After that, in the test_login_petani_setup, I set up a client that will open the login page. I also test the HttpsResponse code should be 200 which means the request is successful(the server received and send an appropriate response). After that in the test_login_petani, using the credential made from the setUp section, I test the functionality of the login function.

After we write our test and make sure that it’s failed, we can start to write our implementation. Always make sure that your implementation won’t break the existing code. It takes time and practices as I said before, so if you still confused or wrong the first time. Don’t be discouraged! Below is my implementation code for the test :

In the implementation (focus on line 1–15) I create the implementation for the test above. First thing first, I have to make sure that the program will send a request to the server. After that, I load the user form that i have created before and make the user that the form is valid. After that, the program will read the username and password input from the user and try to log in with that credential. If the credential is wrong (whether the username or the password is invalid or the username is not available on the database) the program will give an appropriate response to the user so they can retrace what they did wrong.

After we test our code, we can do a double-check to check whether our implementation already correct. There are a lot of tools to do that. But for this project I use coverage, you can get it easily using

pip install coverage

And after that, you can use:

coverage run --source="." manage.py test

To generate the report to HTML format, use:

coverage html

There should be a folder named htmlcov on your parent project directory, open that and search the HTML file that contains your desired test. The green line shows the code covered by the test, and the red one show the uncovered code.

Coverage of the Unit Test

Lastly, the project with Test-Driven Development has its character. Some of their characters are:

  • Version Control log will show every Test-Driven Development stage and any change that was made. For example :
Version Control log showing every stage of Test-Driven Development
  • Code Coverage badge, every project that has a Unit Test in it will show the test coverage. For Example:

We are now have reached the end of this article. So to summarize, test-driven development is a development cycle where the developer makes sure that the test is failing first, and then implement the features around the test. Do the test again and make sure that the second test is passed. Make sure that the new features conform to the first test that was made. The benefits of TDD is the program is less prone to crash and more robust than a program without TDD. That is all I can say about how I implement TDD in my project and I believe you can do it too. Feel free to comment and share the article.

References :

Agile Alliance. (2021, March 4). What is Test Driven Development (TDD)? | Agile Alliance. https://www.agilealliance.org/glossary/tdd/#q=%7E(infinite%7Efalse%7Efilters%7E(postType%7E(%7E’page%7E’post%7E’aa_book%7E’aa_event_session%7E’aa_experience_report%7E’aa_glossary%7E’aa_research_paper%7E’aa_video)%7Etags%7E(%7E’tdd))%7EsearchTerm%7E’%7Esort%7Efalse%7EsortDirection%7E’asc%7Epage%7E1)

Under-graduated Students Majoring in Computer Science