Fast testing not only saves time, but also enables more frequent execution, leading to improved code quality. Optimizing the speed of test execution is therefore critical. While extensive and frequent testing is ideal, it shouldn't excessively slow the pace of development.
Measures
- Test type segregation: Unit tests tend to run much faster than other types of tests. For large test suites, you should consider running unit tests regularly on the developer's local machine, while scheduling more resource-intensive tests in a CI environment. The CI environment can, for example, run the slower tests in parallel and notify you just in case something fails. If the tests take too long for this approach, you can run them at a fixed rate, usually once a day at midnight. Also see Types of Tests.
- Selective Testing: You don't need to run all tests every time. It can be sufficient to run only the tests related to recently changed code, or only the fast tests, and then run all the tests when you finished a major implementation step.
- Mock slow dependencies to minimize code execution time, especially operations such as I/O, transaction management, and networking.
- Prefer in-memory databases during testing for cleaner and faster operations compared to standard databases.
- Identify performance bottlenecks by increasing the number of threads:
- If execution time remains constant, CPU is the bottleneck. Mitigate with faster CPUs, more cores, or additional machines.
- If execution time decreases, I/O is the bottleneck. Use more threads, faster storage (such as SSDs), or additional storage for concurrent filesystem operations.
- Improve I/O speed by using RAM disks, such as Linux's tmpfs tool. Configure your tests to direct all file interactions to the RAM disk.
- Parallelize test execution. Multiple threads can improve execution speed even on single-core processors by keeping the CPU busy while other threads wait for disk I/O.
- Offload CPU-intensive tasks to cloud-based computing resources using automation scripts:
- Upload project files to the cloud.
- The cloud service builds the project, runs tests, and generates a test report.
- Upon completion, download the test report from the cloud.
Asynchronous Testing
Writing new code, executing local tests, waiting for them to finish if they pass going on, is a workflow that works well when the test take a few seconds only. This means this flow is limited to the execution of very fast and sometimes few tests.
- Instead of waiting for your tests to finish locally, you should have a DevOps infrastructure which triggers a CI pipeline when pushing the code executing all tests. Doing that enables you to directly go on working without the need to wait minutes for the tests to finish. In case the CI piepline fails, you should get a notification to fix the CI pipeline immediately. This enables quite comprehensive testing, even having the same testing jobs running in parallel, even long taking ones.