Image by: Real python in testing python code |
Trying to start with a project will always start with few lines of code, then it would eventually grow bigger and unmanageable. That's why writing maintainable and testable code is essential to make our code free from error-prone. In the first part of writing testable javascript, we have seen the basic rule of how to write a clean testable code. Here is a follow-up, the remaining golden rules of writing testable code.
Rule 3: Give what it wants and make it run on only on what is given.
Write functions that run and return results based on only the passed arguments and not on any global variables or any state of the HTML dom. This makes it easier while testing, that you don't need to set up any additional variables or dependencies to run your tests. And as a platinum rule, make your code in a way such that it doesn't alter any external states and all it does is it performs some operation and return the result alone. Make your code independent on external factors and make it doesn't alter any external factors. Because while testing we don't want to be dependent on any external states and not want to alter any external states.
Write functions that run and return results based on only the passed arguments and not on any global variables or any state of the HTML dom. This makes it easier while testing, that you don't need to set up any additional variables or dependencies to run your tests. And as a platinum rule, make your code in a way such that it doesn't alter any external states and all it does is it performs some operation and return the result alone. Make your code independent on external factors and make it doesn't alter any external factors. Because while testing we don't want to be dependent on any external states and not want to alter any external states.
Rule 4: What to do with the heck asynchronous code?
Asynchronous codes take some time to run and return results. For example, consider interaction with the server. If we want to test an API call, whether it is giving the right result or not for a given data, we might not know when will the API fetch finishes and only after the API fetch finishes we may be able to test the result of the call. To help us with this, we may handle asynchronous code with a callback or promises or super cool Async await ES6 function. So that we could see whether the code has ended or not, and it has done the required job or not. As a callback, pass a function that validates the received results.
But even at testing, we must not interact with servers, because we are not testing the servers, we are just testing the call and result. And also the servers may be added up by the burden of handling test requests. But to help us out, there are multiple super libraries like Sinon, Nock, Supertest out there to mock the servers.
Asynchronous codes take some time to run and return results. For example, consider interaction with the server. If we want to test an API call, whether it is giving the right result or not for a given data, we might not know when will the API fetch finishes and only after the API fetch finishes we may be able to test the result of the call. To help us with this, we may handle asynchronous code with a callback or promises or super cool Async await ES6 function. So that we could see whether the code has ended or not, and it has done the required job or not. As a callback, pass a function that validates the received results.
But even at testing, we must not interact with servers, because we are not testing the servers, we are just testing the call and result. And also the servers may be added up by the burden of handling test requests. But to help us out, there are multiple super libraries like Sinon, Nock, Supertest out there to mock the servers.
Rule 5: Inject all the dependencies.
When your function is dependent on any external resources such as database, don't create a database connector globally and use it inside. It makes testing difficult as the same database connector needs to be used for testing which may affect the database. Instead, pass the database connector as an argument so that in testing, a dummy database connector could be created and it could be passed without affecting the external states.
Rule 6: Give it back as it is taken.
Don't change or alter the parameters passed into the function. It makes testing difficult as it affects external parameters. But the thing in Javascript is objects, arrays, and other non-primitive data types are passed by reference to any function that you are calling. So making any change in that functional parameter will definitely change the actual parameter. One way to solve this is by creating a clone inside your function and doing your operation and returning the result.
Rule 7: Write the test first and code next.
Write possible test cases and your test for the requirement before writing code. By doing so, you could dramatically reduce the time spent on revamping or correcting your code for the failed test cases, as you have already written the test cases, you can think of any possible errors and handle it then and there. In this way, you could wrap up all the cases which need to be addressed while testing and could give the exact solution at one stretch.
Write possible test cases and your test for the requirement before writing code. By doing so, you could dramatically reduce the time spent on revamping or correcting your code for the failed test cases, as you have already written the test cases, you can think of any possible errors and handle it then and there. In this way, you could wrap up all the cases which need to be addressed while testing and could give the exact solution at one stretch.
Hope this gives a bird's eye view on how to write testable code to make your life easier. Even though it may look like spending time on writing tests and creating code to pass those tests is not significant,
it will save you a lot of time and sometimes your job too when you are adding a new feature and you want to ensure that you didn't break anything. Because it is difficult to ensure that you have covered all test cases. Hence automating tests is one of the good ways for good project management.
Phew! Where to use this?
Writing testable code is not just for maintainability, it must be used while writing actual tests. For writing tests, there are multiple frameworks like Mocha, Jest, Jasmine. Personally, I recommend using Jest for its simplicity and its backing by Facebook and also its integration with test runner and assertion. So that for beginners to start with their own testing fundamentals, Jest would be very useful without the need of downloading any additional packages. While Mocha and other libraries focus on flexibility and they are very useful in testing huge applications.
PS: This post is based on the knowledge gathered from contents by
Balaji. S. V
Comments
Post a Comment