What is Automated Testing?
Automated testing is the practice of writing code to test our code, and then running those tests in an automated fashion.
With automated testing, you write code and directly call a function with different inputs and verify that the function returns the right output. You can run this test every time you change your code, every time you commit your code to a repository and before deploying your application. With this approach, you can test all the execution paths in a function in less than a second. You can write several hundred or thousands of automated tests for various parts of your application, and run them all in just a few seconds. Automated tests are repeatable.
Benefits of Automated Testing
Why should we write code and test code, when we can just run the application and see the result?
- Automated testing will help in catching bugs before deploying our application. And this is extremely important because it allows you to deploy your application with more confidence.
Note: I'm not saying that with automated tests you're going to release bug-free software. That's not true! But you can certainly reduce the number of bugs and improve the quality of your software.
Another benefit of automated tests is that they allow you to refactor your code with confidence. Refactoring means changing the structure of your code, without changing its behavior. When you don't have automated tests, every time you refactor your code you have to manually test every part of the application that could be affected by your refactoring. And this is very painful because first of all, it's time-consuming, and second, as your application grows, you may forget about the parts that need to be tested. With the automated test, every time you refactor your code, you run your tests and make sure you didn't break anything that used to previously work.
And finally, another benefit of writing tests is that it helps you focus more on the quality of the methods that you're writing. You make sure that every method works with different inputs under varying circumstances.
Types of Tests
In automated testing we have three types of tests:
Unit tests:
Tests a unit of an application without its external dependencies. They are cheap to write and execute fast. This unit test doesn't give a lot of confidence in your application, and when Integration tests come to its rescue.
Integration tests:
Tests the application with its external dependencies. It tests the integration of your application code with this concrete dependency like files, databases, and so on. This test takes longer to execute because they often involve reading or writing to a database, but they give you more confidence in the health of our application.
Traditionally, an integration test is defined as a test that takes a few units or classes and tests their behavior as a whole. Based on this definition, if you test two classes together some people believe you're writing an integration test and not a unit, even if none of these classes talk to an external resource like a database. Chances are you've heard this definition before. This definition is a great recipe for writing fragile tests that are coupled with your implementation detail.
So, as you change the implementation of your classes, these tests are going to break and you will end up wasting a lot of time fixing them. Not only won't they give you any value, but they slow you down.
End-to-end tests
Drives an application through its user interface. They are specific tools built for creating end-to-end tests. One popular tool that you might have heard of is Selenium, which allows us to record the interaction of a user with our application and then play it back and check if the application is returning the right result or not.
These tests give you the greatest amount of confidence about the health of your application, but they have two big problems. The first problem is that they are very slow. Because they require launching the application and testing it through the UI.
So, every test is going to launch the application, login, navigate to an internal page, submit a form and inspect the result. Very slow. The second problem is that they're very brittle because a small enhancement to the application or a small change in the user interface can easily break these tests.
Test Pyramid
Now you know about Unit tests, Integration tests, and End-to-end tests.
What type of tests should you write in your application? Well, all of them.
This is what we call the test pyramid. This pyramid argues that most of your tests should be in the category of unit tests, because these tests are easy to write, and execute quickly. But since they don't give you much confidence about the health of your application, you should have a bunch of integration tests that test the integration of your application code with its external dependencies. These tests provide many advantages of end-to-end tests, but without the complexities of dealing with the user interface.
And finally, you should write very few end-to-end tests for the key functions of the application, but you should not test the edge cases with these end-to-end tests. You only test the happy path and leave the edge cases to unit tests. This pyramid is just a guideline. It's not a hard and fast rule you need to follow in every application. The actual ratio between unit, integration and end-to-end tests depends on your project.
Unit tests are great for quickly testing logic like conditional statements and loops. If you have a methods with complex logic and calculation, you should test them with your unit tests.
This test pyramid gives you three recommendations.
First, is to favor unit tests over UI or end-to-end. Because these unit tests are the fastest to run and cheapest to write, and they're very precise. So they can pinpoint exactly where something fails. They give you rapid feedback.
The second is to cover the unit test gaps with integration tests.
Finally, use end-to-end tests sparingly, only for the key functions of your application. The right balance is different for each project and each team. You need to use your judgment to determine what kind of tests you need to write for different parts of your applications.
Tooling
To write unit and integration tests, you need a test framework.
A test framework gives us a library that include a bunch of utility functions, and use these utility functions to write test. It also gives us a test runner which is a program that we run from the command line, and this test runner executes our test and gives us a report of how many tests pass or fail.
There are similar frameworks in these spaces, the most popular ones are:
Jasmine: Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks.
Mocha: Mocha is a JavaScript-based test framework for Node. js and the browser, making asynchronous testing simple and fun. It allows for flexible and accurate reporting and maps uncaught exceptions to the correct test cases.
You need to use Mocha with plug-ins, the most popular plug-ins used are: Chai and Sinon
Jest: Jest is a delightful JavaScript Testing Framework with a focus on simplicity.
It works with projects using: Babel, TypeScript, Node, React, Angular, Vue and more!
Thanks for reading...
Happy Coding!