Automated tests are rapidly becoming a prerequisite for successful web projects, owing to the proliferation of automated testing tools and an explosion of continuous integration (CI) services that ensure the success of web implementations. Nonetheless, for many developers who are new to the space, automated testing can be an intimidating and altogether novel area that causes more than a few groans at weekly meetings. Luckily, with the right development culture and testing infrastructure in place, your team can focus on implementing new features rather than worrying about the quality of their code.
Yuriy Gerasimov (Senior Back-End Engineer at Tag1 Consulting) delivered a presentation at DrupalCon New Orleans about automated testing and its advantages for web projects of all shapes and sizes. In this four-part blog series, we explore some of the essentials that all developers should be aware of as they explore automated testing as well as the key fundamentals you need to know to incorporate automated testing into your daily workflows. In this second installment, we inspect how to implement a robust testing infrastructure and how to cultivate a development culture favorable to automated testing with the help of code checks.
Key elements of automated testing
Over the course of his career, Yuriy has interacted with a variety of consultancies to gather anecdotal evidence of how automated testing has worked across a range of scenarios. What he discovered is that most orgs tend to implement testing infrastructures and automated testing on a project-by-project basis rather than incorporating it as a part of their regular process for every project. This betrays a fundamental disconnect between the value that automated testing can provide and the inevitable inefficiencies that arise when automated testing is added to individual projects on an ad-hoc basis.
Implementing robust testing infrastructures
One of the classic problems that arise from such a situation is the notion of development teams only implementing a continuous integration (CI) server when customers are able to provide for it in the project budget. In other words, either you can build a server that extends a development culture centered around automated testing, or you risk a scenario in which shared characteristics and shared testing components are absent across projects, requiring you to bootstrap a new infrastructure every time.
Even upon improving quality in your projects thanks to a robust testing infrastructure, code reviews are essential and will allow your interactions between your team’s developers to be elevated to a higher caliber. Unfortunately, however, developers tend not to share substantial knowledge after they complete the features they are tasked to complete. If a developer sees a colleague not following best practices, code reviews can foster improvements in the code thanks to the knowledge that all parties gain in the process. Because of this, Yuriy suggests that development teams leverage a source control provider like GitHub, Bitbucket, or GitLab that incorporates built-in peer reviews functionality.
Fostering a development culture conducive to testing
Development culture is also essential to ensure the success of automated testing. This means that all developers should understand how the testing infrastructure functions in order to guard against regressions. When deployments are not tied to individual team members, for instance, this means that all members of the team understand how deployment occurs and are thus able to implement improvements themselves. For this reason, we discourage blocking deployments on a single function or individual contributor.
The optimal situation is one in which even a project manager who does not write code is capable of initializing deployments and kicking off a series of automated tests. When deployment is automated in this way to the point where even team members uninvolved in development can understand how quality is assessed across the project, this can level up the skill sets of the entire team.
For example, Yuriy recommends that every new developer on a team conduct a deployment themselves in isolation from the rest of the team. By doing so, the least experienced individual contributor may encounter inefficiencies theretofore unaccounted for by other team members and catalyze improvements in the quality of the code. When collaborators who are not yet on-boarded are able to foster advancement in the testing infrastructure across the team, the benefits can not only enrich the automated tests themselves but also cultivate a highly improved development culture across the board.
Considering maintenance costs
Nonetheless, maintenance costs are an important facet of automated testing to consider for any implementation, large or small, because they may be sufficiently exorbitant to encourage recalibration in the testing infrastructure. Some of the key questions to ask include: Do you have enough people to maintain the system from end to end? Do you have a dedicated systems administrator or DevOps specialist who can correct issues when discovered?
After all, testing infrastructures tend to be the components of projects that are scrutinized the least once they are complete—this is part of the blessing and curse of the notion of a “one and done” mindset. In the end, every project has different requirements, and other upcoming projects may demand different systems or other approaches to the same problem. When selecting automated testing systems, therefore, it is essential to consider their impact on the maintenance costs that your team will inevitably incur.
Among the easiest and simplest to implement, code checks are static analyses of code that are not only educational about the code’s quality itself but also can perform very quickly unless your codebase includes hundreds of megabytes of code. As Yuriy notes, in that case, you have other problems to solve first. For many Drupal development teams, code checks for adherence to Drupal coding standards are the first line of defense against potential regressions.
By the same token, security checks, which evaluate the risk of potential vulnerabilities, are also critical. Security checks are capable of verifying that certain best practices are followed when it comes to possible attack vectors, such as the use of globals or session variables in key functions or the allowance of input into deeper recesses of Drupal without proper sanitization. These checks are also convenient in that in many cases, less experienced developers can run security checks and understand the implications of the results without consulting a more senior developer. Along these same lines, linters, which check for syntax errors and the like, can be hugely beneficial for front-end developers.
Complexity metrics and copy-paste detection
Another fascinating selling point for code quality is complexity metrics, which are comprised of assessments of how complex the code is. Among the most important of these is cyclomatic complexity. Consider a scenario in which you have written a function that contains a foreach cycle with multiple control structures (many if-statements) nested within. If your function has many levels of nesting, this can present problems not only in code readability and the likelihood of introducing bugs but also in maintenance. Code checks that analyze cyclomatic complexity can help you to uncover situations in which others would have a horrible experience reading your code by limiting the number of levels that code can be nested (e.g. no more than five levels). Such complexity metrics will aid you in isolating certain logic into other functions or exiting early from your cycles to help your code become more legible.
Finally, copy-paste detection is another hugely useful element of code checking that allows for you to encounter inefficiencies in code. Some developers, for better or worse, often copy and paste code from examples or Stack Overflow responses without necessarily considering how it can best be incorporated into the existing codebase. Copy-paste detection can thus inspect the code to detect code pasted in multiple places; if you use the same piece of code in multiple locations, it may be best to abstract it out by isolating it into another function instead.
All told, code checks are often so immediate that they can take mere fractions of a second. For this reason, they are a ubiquitous element of automated testing and can allow developers to become more productive in a short period of time. In this way, your team can create not only a robust underlying testing infrastructure well-suited for repeatability but also ensure the longevity of a testing-oriented development culture that values consistent code quality.
In this blog post, we covered some of the most crucial elements of any automated testing approach for projects both large and small, namely a robust testing infrastructure and a focused development culture for automated testing. In turn, we looked at the outsized benefits that code checks and security checks can have on your codebase. In the next installment of this four-part blog series, we will devote our attention to some of the other essentials in the testing toolbox: unit testing and functional testing.