Continuous testing is essential for modern software development. Learn eight best practices to maximize success in our free guide.
Continuous testing is a software development practice in which quality assurance efforts are integrated throughout the development cycle. While more traditional testing models involve sending completed code to be independently (and often manually) tested, continuous testing utilizes automated tests to provide developers feedback each time code is submitted to a repository. Its primary goals are to improve software quality and speed up development by catching bugs early, which can shorten feedback loops and reduce bottlenecks.
With the rise of agile methodology and automation within CI/CD pipelines, continuous testing has become an integral part of the software development cycle for many organizations. This article presents eight best practices to consider adopting in your continuous testing strategy. Whether you are new to continuous testing or looking for ways to improve your current approach, we hope these practices will help your organization leverage the many benefits of continuous testing.
The following sections elaborate on the best practices summarized in the table above. They also provide actionable steps to help your organization adopt an effective and efficient continuous testing strategy.
Successfully adopting continuous testing requires an engineering culture devoted to quality assurance. In an ideal scenario, this quality-focused culture would be company-wide and shared among developers, team leads, product managers, and even stakeholders. However, development teams in any organization can benefit from continuous testing with or without support from upper management.
Developers and engineering team leads contribute to this culture in many ways, such as improving test coverage on legacy code, clearly defining and adhering to code quality standards, and embracing quality-driven development practices like test-driven development, pair programming, and code reviews. The development team may also need to advocate for and explain the importance of continuous testing to stakeholders, who may need to adjust budget and timeline expectations accordingly.
In many cases, placing a greater emphasis on QA involves both technical and cultural shifts in how an organization develops software. This can mean onboarding new hires differently and learning new workflows and testing tools.
As with any significant change to team culture and development practices, communication and allowing time to transition are key. Implement new practices gradually, and leave time for feedback and questions on new procedures. Educate all team members on the long-term benefits of automated testing, CI/CD, and other QA efforts. Finally, promote the understanding that software quality is a shared responsibility and requires communication and collaboration among different teams.
With a wide variety of open-source and commercial testing tools available, choosing the correct tools for your team can be daunting. Here are some key factors to consider:
When choosing a testing tool, it is important to consider both your team’s current and future needs, as migrating between tools can take significant developer time. Compatibility with the existing infrastructure, ease of setup, and programming language considerations are vital aspects of the upfront cost of implementing a testing solution. On the other hand, choosing between a code-based and no-code solution can have great implications for which team members will be responsible for testing in the future.
Your team will likely require multiple tools for unit, integration, end-to-end, and UI testing. We recommend focusing on unit testing first because unit tests are the simplest to implement and least expensive to run. If possible, choose a unit testing tool that allows developers to write tests in the same language as that used for production code, such as Mocha for JavaScript, NUnit for .NET languages, or JMockit for Java.
For more sophisticated end-to-end and UI testing, we have included some code and no-code options below.
Code-based:
No-code:
In addition to a testing tool, your team will require one or more QA environments in which to run tests. We recommend using environment as a service (EaaS) capabilities to run tests within ephemeral preview environments—more on this in later sections.
Continuous integration and continuous delivery (CI/CD) rely heavily on continuous testing. Rather than postponing QA efforts to later stages of a software release, continuous testing within a CI/CD pipeline seeks to identify and fix bugs as close to their introduction into a codebase as possible. This results in a more efficient development process.
Implementing continuous testing requires test automation. Some of the most common types of tests to automate include:
Automated tests are run on an individual build as a quality gate before a piece of code can pass to the next stage of the CI/CD pipeline. This can be done locally (often within a container runtime), in a cloud-based environment, or both. An example of a CI/CD release pipeline is shown below.
Continuous testing requires a QA environment to conduct automated and manual testing. Persistent QA environments meet this requirement by mimicking production environments as closely as possible. However, this means deploying multiple versions of the same application on identical and often costly IT infrastructures, which incurs significant deployment and maintenance costs. In addition, using persistent QA environments often leads to bottlenecks when multiple changes to a codebase arrive concurrently.
Using EaaS for testing alleviates these issues by providing ephemeral QA environments that are easily spun up and taken down on demand. The goal is to cut costs and simplify QA workflows by automating the creation of ephemeral QA environments that provide the infrastructure needed to meet the testing requirements for a given feature branch.
EaaS providers help solve these problems by providing the IT infrastructure and software to run an application in an isolated environment. EaaS providers like Uffizzi offer ephemeral preview environments, which can be used to test a particular feature branch in isolation before merging it into a trunk branch. Preview environments can be automatically spun up when a pull request is opened and taken down once tests have passed and the pull request is merged or closed. There is no limit to the number of preview environments that can coexist, so each developer’s code can be tested independently and simultaneously, if necessary. This alleviates or eliminates many financial and workflow difficulties associated with persistent test environments.
To help integrate EaaS into your development and deployment processes, we have included a few best practices below. For a more comprehensive list, see this article on ephemeral environment best practices.
An effective EaaS platform should include infrastructure as code (IaC), meaning that it should be able to provision environments based on an IaC definition such as a Docker Compose file. Once the IaC definition is provided, the EaaS platform can deploy ephemeral versions of your application, containing all of the services, libraries, configuration files, and binaries needed to run the application in a production-like environment.
If your application relies on a stateful database, you will likely need to run test cases with representative data. However, deploying more complex and data-heavy test environments is a costly operation even when using an EaaS provider. It is worth assessing whether your test plan’s data requirements are mission critical; if not, it may be worth scaling back or even eliminating data requirements for a given test environment.
Once you have identified testing goals that require sample data, you will need a way to load persistent test data into ephemeral databases spun up on demand by the EaaS provider. There are a variety of ways to achieve this, including using an ORM with built-in database seeding or loading a dump file. For example, if you are using a SQL database, a SQL dump file stored in an object storage service like Amazon S3 or Google Cloud Storage can be loaded upon container initialization. For more information on this and other seeding methods, see this guide.
As we have seen, continuous testing within a CI/CD pipeline requires a substantial amount of automation. Besides automating test cases, it has become increasingly common to automate build and delivery processes, auto-scaling, configuration management, and other tasks in cloud-based environments. This introduces challenging security concerns best addressed by integrating security efforts throughout development and operations processes. We will examine two ways to address security challenges below.
Continuous security testing (CST) is a security practice that has become essential within CI/CD pipelines. As a form of continuous testing, CST shifts security concerns left to prevent vulnerabilities being introduced into an environment that attackers could target. Continuous security tests monitor your code and application dependencies for security issues and the exposure of sensitive data throughout development and deployment processes. In addition, CST services can be configured to respond automatically to security incidents by removing malware, deactivating services, or installing patches or upgrades to an affected system. Some popular CST tools include Intruder, CrowdStrike, and Snyk.
In contrast to CST’s emphasis on shifting security concerns left, DAST simulates automated attacks on a web application once it is deployed. DAST is a form of black-box security testing, meaning that DAST tools simulate attacks from the outside in and do not require access to the source code. The goals of DAST are to mimic real cyberattacks and find vulnerabilities before they are exploited.
The primary disadvantage of DAST is that, in shifting security concerns right, vulnerabilities are identified late in the development process and can be costly to fix. However, DAST can be extremely helpful in finding runtime and environment-related issues that are not possible to identify before an application is deployed. For this reason, combining DAST with other security practices is highly beneficial.
DevSecOps platforms like GitLab provide DAST analyzers that scan web applications and APIs for vulnerabilities and provide reports on results. If your application is containerized using Docker, DAST can be configured relatively easily within the same YAML file used for the build, test, and deploy stages.
A sample GitLab CI YAML file configuring DAST to scan a web application
Including continuous testing in a CI/CD pipeline does not, in itself, guarantee software quality or a more efficient development process. To leverage these benefits, your continuous testing strategy requires thoughtful implementation and consistent reassessment to ensure that it provides useful information to the right people and helps your product meet your business goals.
If your team is getting started with continuous testing, begin by creating a small number of test cases and add coverage gradually where necessary. It is also recommended to adhere to the principles of the test pyramid, meaning that a larger number of relatively simple and cheap tests is preferable to a smaller number of more complex and expensive tests. For example, running several unit tests is often more efficient than running one integration test, and running a few integration tests is often more efficient than running one end-to-end test.
In addition, your organization may benefit from keeping the following tips in mind:
Addressing these issues in your test plan will help your team avoid writing large, unmanageable test suites that create bottlenecks and slow down development and delivery processes.
Finally, to help your team better understand and reevaluate the effectiveness of your current continuous testing strategy, consider tracking the following metrics:
There is no one-size-fits-all approach to tracking metrics, so be sure to choose the right metrics for your product according to your business goals.
Documentation on test design, coverage, execution, metrics, and results contributes to an effective continuous testing strategy. It removes ambiguity about testing activities, helps onboard new hires, and allows your team to improve your existing testing strategy by examining what is already in place.
However, creating high-quality documentation is time-consuming, so ensure that your team creates only those documents that contribute to product success. To help your team write documentation efficiently, consider the following tips:
Every organization’s needs for test documentation will differ. As with other aspects of the continuous testing process, it is essential to regularly refine your approach to creating and managing test documentation.
Continuous testing is both a development process and a mindset. While it can produce better development efficiency and product quality, continuous testing can be challenging to adopt and maintain effectively. The best practices above will help your organization avoid common pitfalls and successfully integrate continuous testing into current and future software projects.