19 Best Practices for Node.js Automation Testing
Harish Rajora
Posted On: March 7, 2024
144112 Views
19 Min Read
Node.js has become one of the most popular frameworks in JavaScript today. Used by millions of developers, to develop thousands of project, node.js is being extensively used. The more you develop, the better the testing you require to have a smooth, seamless application. This article shares the best practices for the testing node.js in 2024, to deliver a robust web application or website.
Let’s say you developed an application in Node.js about the weather forecast. Testing node.js for a weather forecast application is very complex due to numerous modules and features. For example, the web application will tell you the forecast for today and along with it, it will show you different parameters such as precipitation and humidity. This application will also require location tracking since every user is located at a different location. A user using weather application needs to have correct data because many things works on the weather of the day and of the subsequent days like planning a trip maybe.
A complex weather application might include winds and cloud movements for the geologists to study. An application used at such a level cannot contain a single glitch by which the complete country’s future is predicted. So after the development of these modules, we get to testing node.js for these modules so that everything is checked and works fine in real time.
Hold on now! We are not going to perform testing with node.js on a weather application in this article. However, I will demonstrate a simple project where we will initialize a test in Node JS in small steps so that it becomes clear in the end about how the tests are created for testing Node JS and we can focus on the best practices for testing node.js in 2024.
If you’re new to Selenium and wondering what it is then we recommend checking out our guide – What is Selenium? If you are preparing for an interview you can learn more through Automation Testing Interview Questions.
Initializing A Simple Test In Node JS
If you are new to node.js then here I will initialize a simple test in node.js for you to understand the procedure of testing in node.js. Let us create a basic function of multiplying two numbers:
1 2 3 4 |
function mul(x,y) { return x*y; } |
This is a basic function for multiplication. But, this function is not valid for every case and can stand invalid for various other numbers. We cannot perform testing in such a situation. We will extend this function to validate the equality feature.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function mul(x,y) { return x*y; } function testMul() { var x = 4; var y = 5; val mul = x*y; var mul2 = mul(4,5); if(mul == mul2) console.log(‘Equality Test Passed’); else console.log(‘Equality Test Failed’); } testMul(); |
After writing the basic tests, we will initialise the new node project by hooking it up to the npm.
1 |
npm init |
Now you need to install the modules. As we discuss further in this article you will learn more about the importance of Mocha and Chai in the node js testing. Mocha gives you a good platform to define your test case suites, hooks and use assertion of whatever library you want to use. Chai on the other hand is used for writing the assertions only. These assertions are the human readable test codes which has advantages of its own.
1 |
npm install --save-dev mocha chai |
After this, I have created two js files. One being test.js and other mull.js . Save the test.js in the test folder and mull.js in the root directory.
Now paste the function mul written above with an extra line.
1 2 3 4 5 |
function mul(x,y) { return x*y; } module.exports = mul; |
Exporting it will help us in adding it to the require line as we perform testing with node.js.
Open your test.js file in the tests folder and write the following test code given below to go-ahead testing with node.js. This test code will test the equality of the two functions. The expect variable is the object code from chai library to write the “expect” part of the assertion and multiply will be the variable that contains the exported module of the code given just above it (module.exports = mul).
1 2 3 4 5 6 7 8 9 10 11 |
var expect = require(‘chai’).expect; var multiply = require(‘../mul’); describe(‘mul()’, function(){ it(‘should multiply two number’, function(){ var x = 4; var y = 5; val mul = x*y; var mul2 = mul(4,5); expect(mul2).to.be.equal(mul) }); }); |
Just run your tests now through npm test in the console window and you are good to go.
Automate your app tests over 3000+ real devices and OS configurations. Try LambdaTest Now!
Best Practices For Testing Node JS
Testing tells the stability of your application and if not, makes it more stable which in turn save you from a sudden wrong commit which can take the whole software down with it. Testing is required before you push your code to your users so that no one is bugged by any of the unwanted behaviour of the application. Being this important, we will see some of the best practices for testing Node JS in 2024.
Isolated and Atomic
Test should be atomic and isolated. Every test should run independently and without being dependant on each other. If neither test is dependent on any other test then if one test fails, other tests are not affected. Also, the tests should follow the atomicity property. It should not fail in between suddenly. A test should be entered and exited with the pass or fail result smoothly.
You should also keep in mind that the data you are testing upon should be separate for every test. More than one tests working on the same global data harms the overall motive of using the tests upon the application. Your time will absolutely increase leading to good performance but it is of no point. Keep your data specific to the tests.
Naming Of Your Test
This is one of the most basic and important feature for writing effective test cases. A test should be named meaningful and easily understood by other departments who are not related to testing such as development team. A name should not be any random name such as foo() being used popularly. After seeing that your test is no random word, you should focus on what you should name your test. A test name should constitutes of
- What is being tested?
- What are the different scenarios under which you are testing?
- What should be the expected result of the test?
Here is an example of a meaningful naming convention for testing node.js.
1 2 3 4 |
function CheckCountryLanguage() { //code to check if the application is showing data in the country’s official language } |
The above test name makes sense because we can easily get what that function would be doing. What if I had written the function name as foo? Then I would have to read the complete code to understand the working of the function.
Using Assertions
An assertion in the programming language is a statement for which we declare at the time of coding. This declaration may or may not be true and hence provides the boolean output with true or false. The declaration itself contains the meaning of the test code such as expect(‘age’).to.be.equal(23). This is self-explanatory and cuts the code lines’ logic to a great extent. If the variable ‘age’ is equal to 23 then True is printed or else False. You can learn about assertion here. Assertions are more beneficial than normal tests because they already provide a statement in the test case. Also, when an assertion is run, you don’t need to know what was the response and why you got it. It would just provide you whether the test failed or passed.
A test will use logic in test cases while assertions are the human readable forms where you write tests in human readable forms. This helps when analyzing the tests after they are run. You can use chai library for achieving the same and can learn more about the Chai library here.
1 |
expect(‘currentweather’).to.be(‘string’); |
Such assertions are human readable and are self-explanatory about the test they are performing. This expect shows that the currentWeather has to be a string such as Hazy, Clear or Rainy etc.
Use Test Runner
A test runner is a library or a tool that takes a source code directory which contains the unit tests and runs tests on it. After executing the tests, it writes the results back on the console or the log files. It is always recommended to use a good test runner and some of the testers use their own test runners too. While having a test runner can be advantageous with the databases as it can take the database values (dummy or real) and execute different tests on it. It can load fixtures too. Mocha is a test runner. Mocha can provide you a programmatic way to run the tests via command line tools on ES6 codebase.
Focus On Test Coverage
A test coverage while writing the tests is the amount of source code you are covering in your test. In simple words it can also be said the amount of application as a whole you are covering for your test. While writing the tests, it is considered the most important thing to work upon. So how can you increase your test coverage?
First of all, you should always keep in mind that test coverage percentage is totally depended upon the nature of your application. If it is some application say Music Player then it need not have 100% test coverage because as we increase the test coverage it becomes more and more expensive for the company. But if you have an important application like any real time application receiving data from satellite or an application for the manufacturer of Airplanes then you need to have 100% coverage because it will affect the application to a great extent. We will focus on test coverage for the upcoming points. For this you can use Mocha along with Istanbul and run your Mocha tests over Istanbul.
Use Plugins For Test Coverage
Plugins are available which tests all the test coverage. Plugins will not help you in writing the tests that covers maximum code but it will definitely help you analyze your test and tell you if a test is skipped or not. It will also show if all the test cases are covered or not. This way you might be thinking that you have written the tests that covers some percentage of the code but in reality some tests are skipped bringing down the overall percentage.
Analyse The Test Coverage Report
A test coverage report can be generated with the help of Istanbul and Mocha. Once you have generated the test coverage report, try to analyze the report. A report with say 90% test coverage that you might think will not be covering the complete 90% code with its test cases. While using Istanbul it is quite easy and straightforward to analyse the test coverage report. Also, you should take the failed test seriously and analyse them as to why did they fail and check if there is an issue or not.
Use Mutation Testing
Mutation testing is the type of testing in which the test cases’ logical condition are tweaked (mutated) to deliberately fail the tests or if it failed then to pass it. The logics can also be changed for the same reasons. It is also popularly called as planting a bug. There are various libraries that you can get on the internet but one of them and most popular being Stryker can be used for the same purpose.
Check Plagiarism On Tests
While testing node.js on the source code, you should always check for plagiarism on the code. It is not so uncommon to copy and paste the code from the internet to make the software work. You might never know the source code can be licensed and your organisation can fall into serious trouble for the same. These things violate the copyright issues also. So always remember to check the code for plagiarism in order to tweak the code a little but for the advantage of your organisation.
In order to use the plagiarism checker, you can install the node js npm plagiarism-checker package.
To install it just type the following code:
1 |
npm i plagiarism-checker |
After that, in order to use that SDK, type the following code:
1 2 3 |
var a = require('plagiarism-checker'); var b = new a(); var config = b.getConfig(); |
Download the code from this repository and add it to your project. Keep in mind the following dependencies are installed
1 2 3 4 |
$ npm install lodash $ npm install request $ npm install request-promise $ npm install mime-types |
Use Realistic Inputs
Many times it so happens that the testers use the inputs that are not realistic or according to the real life scenarios. For example an input demanding phone numbers should be tested on numbers which resemble the real phone numbers. So you should always use realistic inputs while testing your application. The best library available for this purpose is Faker library. According to GitHub, Faker library is a php library that generates fake data for the input you are willing to test upon.
You should also keep in mind to use more and more inputs for a single input parameter so as to test heavily. As in real life, many inputs will be processed on the same function, you should use as many as possible to test them.
A simple portrayal of the situation can be the same weather application that we discussed in the beginning of this chapter.
1 2 3 4 |
function CountryName(string country) { //code } |
Now, this function should be tested with realistic inputs such as
1 2 3 4 5 6 7 8 |
function CountryName(India) { //code } function CountryName(Netherlands) { //code } |
Instead of :
1 2 3 4 5 6 7 8 |
function CountryName(abc) { //code } function CountryName(foo) { //code } |
Use Linters
According to Wikipedia, linter is a tool that analyzes the source code to flag programming errors, bugs, stylistic errors and suspicious constructs. Linters are great at finding certain classes of bugs including assignment to undeclared variable and use of undefined variables. Using linters can help you a lot in determining the bugs in the structural way of the code. For Node JS, you can use ESLint for the same purpose.
Property Based Testing
Property based testing depends on different properties of the function. It is used to check the property of the entity (function, program etc) in particular. A property is a characteristic of the entity. For example, if you have a function that takes the input arguments as a,b and holds the property that b is always even then by property based checking, we check whether b is always even or not.
for all(a,b)
b is always an even number
Property based testing helps us as it
- Contains the scope of all inputs and that can generate a huge number of test cases
- Can take us to the failure in a very short time as it has something specific to put as the input like even numbers in the above case. It can keep on inserting even numbers until a point that it fails and we can get the threshold value of the function quite easily.
You can use FastCheck, QuickCheck or Mocha Test Check for property based testing.
Use Chai Library
Error catching should be done with specific libraries such as Chai library. It expects the assertions and hence give you what the error was about. This might not be the case with try-catch-finally statement. A Try-Catch-Finally statement will throw some generic error statement because it takes the exceptions as a whole class of exceptions and errors and does not give the specific result about the same. It then takes lot of time to decode what the error was actually about.
For example,
1 |
expect(‘a’).to.not.have.property(‘b’); |
this way few lines of code is summarised to a single line of chai assertion.
Check For Exceptional Scenarios
While the test cases and scenarios that you design might cover everything on the source code but there are few exceptions that are very important while testing the application behaviour/response/outcome. Let say there is a feature in your application that sends email when a new user is added. The email is sent to both admin and the user. This becomes an exceptional scenario as the method must be passing correctly but you might not be getting any email. These things should be tested. The testing should also include forcefully sending different response code from the server side so that we can know how the application behaves in such a way and what values are returned. If you go to the normal approach of checking the JS conditions and test cases internally then you will be able to check the internal conditioning but will never get if your application behaves in the same way practically or not.
Many firms develop their own methods to achieve these things. A good example is Netflix which has developed something they call Chaos Engineering which tests their functions and method by killing off their servers one by one. This way they are also assured that even if one server fails, the application works correctly.
Follow The Testing Pyramid
While testing with node.js, you should try to follow the test automation pyramid. As seen from the following image the unit test should be taken as the base of all the testing.
We do so because unit test will cover the basic units of functionality independently of one another. After the unit tests are done then move ahead to the integration testing. Integration testing will let you test the different modules combined with one another as a group. After that we move on to the next part of the pyramid and test the front-end or User-Interface testing using Selenium or similar tools.
As you can see, the cost incurred keeps on increasing as we move on to the pyramid but the speed keeps on decreasing. Unit test takes most of the time to execute while the front end is tested fastest because of the less complexities and modules.
Use Component Testing
Component testing tests the functionality of the modules which are separately testable. The input/output behaviour of the test object is verified by the component testing.
As seen in the image, each component has a test plan and every test plan has various different tests under it and then they are tested to check the functionality of the component. It is recommended to use the component testing after the unit testing in the pyramid. Component testing is a very good approach and has a great coverage and speed greater than unit testing.
Keep Infrastructure Issues In Mind
More often, testers think that the testing of source code with the above practices kept in mind is the all they have to do for the proper functioning of the application. But, they are wrong. Testers tend to forget the infrastructure issues and testing them which have a great percentage of happening in the real life practical scenarios. These infrastructure issues include memory overloading and how the application behaves when it happens. Other infrastructure issues may include the sudden shutdown of the server or API becoming 50% slower which is used in the application. Infrastructure testing include testing of these issues and providing a feedback report on it so that they can efficiently managed.
Going Parallel
Parallel testing means running multiple test cases, simultaneously. Running different tests in parallel has its own advantages. If you are not following parallelism then you will run one test and provide the feedback about it then you will run another tests and provide feedback about it and so on. These feedbacks are then analysed and are worked upon. Then the team will check the feedback of the second test you did and then resolve them. While following parallelism, you can drastically reduce the feedback loop and provide feedback of many tests altogether which can be resolved in a lesser time as before. This way you can save a lot of time and resources of the company. Many libraries are available for achieving parallel testing, most popular of them being Mocha and Jest.
Automate The Updation Of Your Dependencies
Running the tests and following different rules require lot of libraries and different tools to work altogether in order to achieve the perfect testing. But it sometimes happen that the dependencies become out of date and other dependency require the latest version to run with each other. This creates disturbance in the smooth running of the tests and can be resolved by automating the updation of your dependencies. Once you automate the updation, every dependency will update by itself and will not require to manual intervention after raising the flag for the same.
Use An Online Selenium Grid For Cross Browser Testing
Talking about automation, everyone favors Selenium as an open-source for performing cross browser testing. However, there are a limitation on the number of browser and machines you get access to as you go ahead setting up your Selenium grid. Performing a thorough round of automated cross browser testing calls for a cloud-based provider such as LambdaTest.
LambdaTest is an AI-powered test orchestration and execution platform that lets you run manual and automated tests at scale on over 3000 real devices , browsers, and OS combinations. You can automate your testing process and can even perform testing with node.js in parallel. You can even perform test using any other test automation framework with respect to different languages such as Python, PHP, C#, Java and more.
Well, that was all from my end. Testing with node.js may look a little scary at first. However, you can get rid of hesitation and perform it like a professional by keeping the above best practices for testing Node JS in mind. Let me know if there is a special practice that I have missed, and you feel is indispensable for the article. Happy testing! 🙂
Got Questions? Drop them on LambdaTest Community. Visit now