Ever wondered a way to write the test cases for the scenarios that you actually dev test manually ? What if I tell you a way where you can write the test cases which will ensure that the code you have written is checked and gives you a way to validate your logic? Sounds cool right? TDD is one such approach where you can do the above said with some little extra efforts which in turn will get you the validation that would help you to not worry about the logic written ever again.
TDD is the short form of Test Driven Development. It is an approach where you write the test cases for a requirement first and then jump on to writing the actual logic. It is one of the core principle of extreme programming. Unit test cases and refactoring done on detection of logical or actual error are part of TDD itself.
In this blog we’ll cover some important aspects of TDD for the Android Apps written in Kotlin. Why is it important and why should you do it ? So without a further ado let’s jump in.
TDD ensures effective unit testing and consists of short development iterations. TDD is nothing but a technique of TFD (Test First Development) and Refactoring together. TDD promotes improved code quality because of the extensive verification that is performed.
Benefits of TDD
- Extensive verification of code — TDD approach ensures that every bit of your code runs through a test.
- Overall good code coverage — With TDD almost 100% of code coverage is achieved.
- Software becomes more modular & easier to maintain — To test the code in TDD you have to divide the large code into smaller chunks/ methods making to more easy to understand and test.
- Enables the code to get refactored more smoothly & quickly — Since writing the test cases enables you to understand the code fully, it becomes easier for you to know the affected region before you refactor the code. Hence omitting the possibility of erroneous code.
- Lesser debugging & reduces the possibility of error by 50 to 80% — Using the approach where you fail the test cases deliberately before writing the actual logic. You exactly know what shouldn’t be done, hence reducing the chance of writing the code full of bugs.
- Helps with CI/CD — Implementing CI/CD on your code requires to write test cases, hence by following the TDD approach your hassle to implement CI/CD reduces significantly.
- Makes you a better developer — Because before writing the actual logic you’re evaluating the edge cases through which your logic will run which makes you more sharp with the actions you take and hence a better developer than rest.
- Improves the critical thinking (instills Think twice, code once mentality).
Installing the dependencies
In the later part of the blog we’ll see the actual implementation of an Android app written purely in Kotlin. So before you go ahead, please install the following dependencies in your app level build.gradle file.
- Junit: It is a unit testing framework for Java applications. It is an automation framework for unit as well as UI testing. It contains annotations such as @Test, @Before, @After, etc.
- Mockito: Mockito mocks (or fakes) the dependencies required by the class being tested.
Let’s get started
Ideally, test cases are written before writing the actual logic inside the method. But for the sake of explanation I have written down the code below first.
Unit testing is done to ensure that the developer would be unable to write low quality/ erroneous code. It makes sense to write Unit Tests before writing the actual logic as then you wouldn’t have a bias towards the success of your tests, you will write tests beforehand without making many mistakes.
Let us understand the approach using an example written below-
The code contains the logic for the screen where the user inputs their phone number post which an API call to server will be made where the user will get a verification code from requestForVerificationCode()
method.
The response of the API call will be passed into checkApiResults()
method where it is checked for success or error.
On getting the success response from the server user will be redirected to the next screen using navigateToNextScreen()
method. In other cases where an error response is obtained from the server or if there’s a network error the user will be shown a snack bar using showSnackbarForApiError()
and showSnackbarNetworkError()
methods respectively on the current screen notifying them of the same.
Operations performed on the snack bar is done with the help of view state file where current state of the screen is stored using the data binding approach.
For the above code, the possible scenarios that you can test are
- Check if
requestForVerificationCode()
method is invoked/ called or not - Check if network error occurs when internet connectivity is not there.
- Check if navigation to next screen happens when success response from the API is obtained.
In the code below I have divided each test case in 3 parts namely — Given, When & Then.
- Given — Defines the default that we provide when an API call is made or in other words how the data will actually look like in our modal class is kept in this section.
- When — Defines the call to the method containing logic in the actual class for which we are writing the test cases.
- Then — Defines the statements where we check the equality of the output with what the expected output should be.
I have used the mockito library to mock the behavior of certain classes because we cannot call the actual implementation of it inside the test cases.
I have used assert statements from the Hamcrest class which will help us knowing the equality between expected and obtained output.
Here we have covered all the scenarios discussed above. If you want to dive more deeper into test cases, please go through the below links.
Disadvantages of TDD
As no software development practice is 100% accurate, the same goes with TDD as well. It has some disadvantages to it such as,
- Difficult approach to adopt & Increases the development time.
- Tests need to be changed when the requirement changes.
- All the developers working on the project with the approach of TDD are bound to do it.
Above mentioned may sound a bit overwhelming but this is nothing compared to the advantages TDD comes with.
Initially, it is difficult to understand the approach but once you get the hold of it your thought process for executing the task will become much more clear. Once you’re clear about what you should be doing, the execution speed increases drastically and the scope of bugs/ errors also reduces with it.
Also instilling this approach in entry-level developers will make them sharp and better in the longer run. It’s a win-win for everyone when you adopt this approach because the testing and bug fixing reduces when the code goes to testers as you have almost covered everything from your end. This in turn ensures an end product with the least or no amount of faults.
Conclusion
So we saw what is TDD, how it is useful to us in so many ways, and why it is a fastest-growing favorite for developers. I was a bit skeptical if we should go with this approach in the first place as it was a cumbersome task to first understand its nitty-gritty and then implement it on the go. But I am glad that I did as at the end of the process I have come out as a better developer. Also, it helped me to write code that is less erroneous which in turn proved good for the project as well.
Hence we have covered almost all the important aspects of TDD. If something is missing please feel free to add it in the comments. Would love to talk with y’all. Also if you found this blog useful in any capacity, feel free to give the claps as it boosts my motivation to write more.
Cheers & Happy coding.
For more information or Have an idea for the app? Contact us