Did you know that there's an easy way to add quality, speed, reliability, documentation, and long-term value to your software? These three automated tests give you the feedback you need.
"If a software doesn’t work as expected, it doesn’t matter how beautiful or fast it is.” That's a good rule of thumb to live by, but how can developers ensure they follow it? The answer is simple: automated tests.
Automated tests are programs that automate the task of testing your software, and they matter because they give developers quick feedback on errors. They interface with applications to perform actions and compare the actual result with the expected output you've previously defined. Thus, automated tests enable fast error feedback on the code developed, making the development process more reliable. In other words, developers can see errors quickly and fix them before software goes to production.
Automated testing is also useful when integrating new features into your software. When the integration of features is being done, the written tests can ascertain which parts of the software will break after the integration. Otherwise, if the tests are done manually, the team would need to test the integration at least three times: in a new feature created, in an old feature integrated, and in between both parts.
Testing manually is not only time consuming, but it's also error-prone. After all, the tester would have to follow the same user path manually without making any mistakes to ensure that the integration is a success.
So, developing an application driven by automated tests can provide many benefits, including:
There are many ways to classify tests, but the following three suggestions provide a solid framework for dividing your tests into separate categories:
Unit tests are the smallest portion of a test that can be written. The main goal of these tests is to create a formal and official registry of the code as a live document. Instead of having to register the code elsewhere, you can register the code documentation as tests. Thus, you don't need to explain how the code works in another document other than the test suites themselves.
Unit tests can only test part of the application and should not have broad coverage. Thus, they are recurrent and frequent.
Unit tests can also test individual functionalities in the software. They are very quick to run and can run many times during the development of a function. They are easy to understand, cheap to develop, and quick to update and run.
Integration tests verify the observable behavior and the integration between multiple functions. Thus, they offer broader coverage and are run less frequently. They guarantee adequate usage of third-party libraries and check whether the unit being tested performs the expected functionality.
Integration tests take more time to run (a few seconds). They are "medium-sized" tests and cost a little bit more to develop.
E2E tests verify the whole feature in the same way that a user would experience the application. They should be run when a feature is completed, as they check whether or not the feature is correct. They are more expensive to develop, take a long time to run, and are run fewer times during the project lifecycle.
So, let’s take a look at how to write tests on the frontend using a popular framework like react.js.
In this example, we are going to use Jest and Enzyme together with React.js:
In the terminal or command prompt, install the following dependencies to your existing create-react-app project.
npm install enzyme enzyme-adapter-react-16 enzyme-to-json --save-dev |
or using yarn
yarn add enzyme enzyme-adapter-react-16 react-test-renderer enzyme-to-json --dev |
Please note: If you created your app using create-react-app, you don’t need to install Jest. It already comes installed by default.
Next, let’s configure Jest and Enzyme to work together with React.
In the src/ directory, create a new file called setupTests.js
import { configure } from 'enzyme'; |
In the package.json file, add the following Jest configuration:
"jest": { |
enzyme-to-json helps make Snapshot tests more readable; by adding it to the snapshotSerializers, it is automatically applied to each Snapshot test via the configuration above.
collectCoverageFrom indicates which set of files coverage information should be collected for. In our case, we have restricted Jest to run on all files with the .js extension except src/index.js, as it is usually just boilerplate code, which doesn’t need to be tested.
coverageReporters tells Jest to output the coverage report via terminal instead of creating an HTML page to display these results. As a developer, it is much easier to check the terminal to understand where you stand in terms of test coverage.
Let’s say we have a component called DefaultText.js
import React from 'react'; const DefaultText = ({ children }) => ( export default DefaultText; |
To create our first test, we will create a new file called DefaultText.test.js; this will be collocated next to the DefaultText.js component file.
import React from 'react'; const title = 'Test DefaultText'; describe('DefaultText', () => { |
The first block will create a new snapshot of the DefaultText component.
The second block will do an assertion to check if the value in h1 is equal to the variable named title, which stores ‘Test DefaultText’. If true, the test will pass.
Type npm test in the root directory of your project via cmd/terminal. This will run all the test files in the CRA project and output the results to the terminal/cmd.
Run npm test --watchAll --coverageReport to generate a code coverage report. This report will show in-depth information about each file, including statement, branch, functions, and line coverage percentage.
I hope you enjoyed this practical tour of the three automated tests every developer should know and use. If you use these tests, you can feel confident that your applications are less error prone and that your developing process is stronger, faster, and smarter.