Stress-Free Unit Testing in Drupal: Test Helpers Module

Jun 06, 2024
By Taylor Payne
Drupal

The journey of testing methodologies underscores the importance of ensuring code reliability and functionality, especially in the complex landscape of Drupal development. 

In the ever-evolving landscape of software development, where elements like reliability and functionality are imperative, the role of testing emerges as indispensable. Testing serves as the cornerstone, ensuring that our code operates with precision and reliability, preventing potential pitfalls before they escalate into significant issues. Within the complex framework of Drupal and WordPress development, testing becomes more of a significance, transcending from a nice-to-have to being imperative.

Recently, our team at Five Jars delved into the ins and outs of testing methodologies, with a particular emphasis on Unit testing—the cornerstone of robust software engineering practices. 

One might think to themselves: “Why should I spend time writing tests?” Although incorporating tests into our development workflow isn’t always smooth sailing, without tests, our code's integrity remains unverified, leaving us vulnerable to bugs and glitches. Tests can act as a tool to provide proof that each function does exactly what it is designed to do at any given time. 

Test-Driven Development (TDD)

TDD is a development approach that allows developers to create specifications around how their code should work, be written, and be implemented. Fundamentally, TDD is a standard of a programmer writing a functional test during beginning a code build, which will assist with:

  1. Elevated code design. When writing a code test, developers first define a goal to achieve within the code piece, uplifting overall code design.
  2. Detailed project documentation. When writing tests for particular requirements, teams will create strict and detailed specifications, including all the likely software functions.
  3. Development time. As the project progresses, new features are sure to be added and tested, increasing the software delivery speed.
  4. Code flexibility and easier maintenance. Testing allows developers to perform faster refactoring, more accessible code learning, and minor debugging.
  5. Long-term savings on project costs. By implementing stronger and more frequent testing, developers can strive for fewer bugs, reducing business costs.
Graph of cost of change vs. development time showing a lower amount of development time with the TDD approach

The Testing Pyramid

The testing pyramid advocates for a greater emphasis on lower-level tests, such as unit tests, and fewer high-level tests, such as functional tests:

Pyramid graph showcasing from top to bottom: End-to-end testing, integration testing, resting on the foundation of Unit Testing
  1. Unit Tests: This focuses on a single functionality and small units of code. Typically, there are several of these units, but are relatively quick to write and execute.
  2. Integration Tests: This step checks the interaction between different modules or external systems. Settling in the middle of the pyramid, these tests are fewer than Unit Tests, are more expensive, and slower to execute. 
  3. End-to-End (E2E) Tests: This involves checking the entire application as end-users would experience it; i.e. user interfaces, APIs, databases, etc. This step is the most complex and requires the longest execution time.

This approach helps maintain a balance between test coverage, test execution time, and test maintenance effort. By focusing on a stronger foundation of unit tests, developers can catch most bugs early in the development process, leading to more robust and maintainable codebases.

Contracts

Now, how can an isolated Unit Test tell us that the entire solution is working correctly? Defining mock objects allows developers to test logical relationships in an isolated environment using a contract between related objects. For example, these contracts can be implemented using a mock of an object interface.

Graph showcasing: Service 1 & 2 going into Unit Tests going into Service 2 method, going into Mocks of Service 1 & 2 within the Contract

Contracts allow us to achieve 100% test coverage for critical business logic. If every object and object contract has been tested, then the layer has been tested, and the entire solution is tested and works as designed.

Graph showing how Service 1 & 2 tests work within two different layers

Drupal Test Helpers Module

In the case of Drupal, a classic Unit Test for only one simple legacy function is very long, complicated, and oftentimes unreadable. For example, a 30-line function could require 136 lines to test. The solution is utilizing the Drupal Test Helpers module. This module provides API information to significantly improve the simplicity of writing Drupal Unit Tests; reducing the amount of code, covering all the logic of tested functions, and using provided stubs of Drupal services.

Using the 30-line function from legacy code as an example; to create a classic Unit test requires 136 lines of code, whereas with the Drupal Test Helpers module this drops to 42 lines.

Picture illustrating how the amount of code lines are decreased

While this module will not solve all problems associated with Drupal Unit Tests, it is sure to make processes significantly easier with a small execution time and short, readable tests. Additionally, all helper functions are static and can be used without module installation, allowing developers to simply require the module the “require-dev” section.


Features and Benefits

  • All features from classic Unit Tests. Allows developers to still test isolated units of code without relying on Drupal core. 
  • Easy service dependency injections. All services using Helper functions automatically load dependent core services as well as services provided by the module of called services. There are also possible solutions to override some dependent services easily.
  • Smooth mock object creation. Easily allows entity mock creation and mock entity methods. 
  • Drives better code performance. An inefficient code requires an inefficient test. With a better testing foundation, it is possible to have a deeper understanding of the logic and how it must be separated or moved to a standalone object or method.

How Five Jars Implements TDD

In our development of the ScreenPulse project at Five Jars, the TDD approach is utilized in a variety of ways, including:

  • The critical business logic separated from Drupal, ensuring 100% test coverage
  • Refactoring of the architecture and testing consistently to ensure the project continues to work as designed
  • Implementing the Drupal Test Helper Module to provide the possibility of applying the TDD approach during Drupal development

With our testing foundation, we have 48 unit, 5 kernel, and 3 functional tests, as well as big plans for refactoring with test coverage. 

Graph showing how Drupal unit and kernel tests decrease the amount of time spent on tests

What’s next?


The journey of testing methodologies underscores the importance of ensuring code reliability and functionality, especially in the complex landscape of Drupal development. TDD acts as a guiding principle, driving elevated and straightforward code design, detailed project documentation, accelerated timelines, and enhanced code flexibility. Building a strong foundation with the Testing Pyramid provides a framework to prioritize tests, with a focus on Unit Tests to fortify codebases against potential issues. This, alongside the Drupal Test Helper module, allows developers to beef up their testing process and drive toward tested projects that are more resilient and reliable.
 

Picture of Oleksandr Riumshyn, Software Engineer
Oleksandr Riumshyn
Fullstack developer with 9 years of experience specializing in Drupal. He is passionate about different development approaches, innovation and seeks new challenges.
Photo of Taylor Payne, Digital Marketing Manager at Five Jars
Taylor Payne
A true Marketing Nerd™ with over 8 years of experience in strategy, branding, and implementation. The only constant in this industry is change, and how exciting is that! Taylor navigates her goals with intrinsic motivation, eager to see her team succeed on whichever path they're on.

LET'S CONNECT

Get a stunning website, integrate with your tools,
measure, optimize and focus on success!