The Lessons I Got With Test-Driven Development
This article was written as an individual review assignment of PPL CSUI 2021
I have known test-driven development for the last few years since I was studying computer science. I also have learned that a few times but I still do not understand it at the time. Even so, I have done several projects using TDD and have no idea what it does at all. However, my ignorance ended when I was working on my current Pantau Peradilanmu project.
While working on the Pantau Peradilanmu project, I understand the benefits of using TDD. There is something new that I get when I do TDD. I realize TDD is not something that difficult, but something that will help us to make the best application that fits our expectations and every stakeholder. The following are the benefits I get when I work on the Pantau Peradilanmu project.
Fulfills the acceptance criteria specified by the product owner
When I was working on this PPL project, I always started by making tests for all implementations. I made these tests following the acceptance criteria from the product owner. For example, when I worked on the login page, my product owner gave acceptance criteria “If the email or password is entered incorrectly, the system will notify you with an incorrect email and password.” and “Show / hide password”. So I made a test for it with the code below.
With this test, while making each implementation code, I will always meet the acceptance criteria that have been given. Also, by doing TDD, I will be calmer in working on my projects because CI scripts need to run tests before deploying / building applications. It also makes the application that I created a testable application that has already thought through the tests and will not be deployed and built if it does not meet the tests and criteria. Here is a snippet of my team’s CI script to do TDD.
Make applications that match our expectation
When working on Pantau Peradilanmu, my dev team and I created the high-fidelity design of the application. That makes me already had my expectations for the application. I hope that what I make will be following our design and will not deviate far from the design. Therefore, I need to test the expectations on an application page and if I forget to meet the initial expectations and the test failed, I will look back at code implementation of what did not meet the initial expectations
For example, the login page above. On that page, I hope there are the words “Selamat Datang,” and “Log In” so before making the implementation, I will make a test to get the keys of the two sentences. Also, I made a test about the expectations of the widgets that will be on the login page, such as there, textButton, textField, and the Custom button that I made. Therefore, I made a test to check these things as below.
You can also see that we can test and find the widgets on a page with FindsOneWidget, FindWidget, and FindNWidget (n) according to our needs.
expect(find.byKey(Key('Log_In')), findsOneWidgets);expect(find.byType(TextField), findsNWidgets(2));expect(find.byType(PrimButton), findsWidgets);
Make quality improved and bugs reduced.
When I make a test first, I know that I’m making a good quality standard for the application. Therefore, I make tests for all possible things to happen and based on the quality I expect for a task. In the end, the qualities that I was expecting in the test will improve the quality of the code I create next. Test-driven development also helps me reduce bugs and code smell when I finish implementing because I have already thought about the things that are going to happen and how we handle them with the appropriate output.
After implementing, I usually look at Sonarqube to check for bugs and code smells in my work. Like the picture above, there are no bugs and code smells for the code that I made. In the end, the results of the test were seen when my team and I did a sprint review. The Good code quality and good application make product owners and clients feel satisfied with the temporary application and have no complaints about the application.
Make us more agile
I am working on this Pantau Peradilanmu project with agile development so that sometimes there are changes in requirements and implementation. In the process, my code will be used and developed by other group members so that testing it makes the code ready to maintain code consistency in case of changes and becomes our starting point for knowing what a piece of code does. As a result, I am not confused about code generated by other people and do not need to ask questions about what a piece of code does. It also allows us to work quickly and smoothly because it is faster to understand the code we are going to use.
How I implement TDD in my project
In implementing TDD, there is a circle of life that needs to be done. It is usually called the Red — Green — Refactor cycle. Usually, before starting to code, I will understand the user story and task to find the criteria and design for the task I will be working on. Then I will try to make the test first by adjusting the design and criteria that I have obtained previously and making the test fail because there is no implementation yet. This stage is usually called the red stage.
Then, I create a code implementation that can resolve the previous tests that I made and try to run the tests. When all the tests have passed, this stage is called the GREEN stage.
Finally, sometimes I need to improve some code implementation. That stage is called the REFACTOR stage to improve some code implementation and keep the tests passing. Also, there are times when I only add dependencies that don’t affect code implementation and can be called commits as CHORES.
I keep repeating each of these stages when I want to implement the code so that it always fulfills a good TDD cycle.
Meet the F.I.R.S.T Principle
When I make tests, I always try to meet the F.I.R.S.T Principle and get the benefits I have mentioned before. Here are the details of the F.I.R.S.T Principle.
- [F]ast, tests should be fast otherwise they will slow down my development/deployment time.
- [I]solated, Never write tests which depend on other test cases.
- [R]epeatable. A repeatable test produces the same results each time you run it.
- [S]elf-validating. Each test must be able to determine that the output is expected or not. It must determine it is failed or pass.
- [T]imely. As I said before we must create the test in a timely fashion which is before the code is production-ready.
Thank you for reading my Test-Driven Development article. I hope this article about the lessons I learned can help you understand the benefits of test-driven development and start doing test-driven development.
- Buku Panduan Git Flow PPL 2021
- Buku Panduan Git Deployment PPL 2021
- Buku Panduan Definition of Done PPL 2021