Automated testing is the process of creating and implementing code to decrease the manual human effort needed during software testing. This vital approach plays a crucial role in modern software development, where specialized tools and scripts are used to execute test cases, validate functionality, and identify potential issues. By automating repetitive and time-consuming tasks, significantly reduces the manual effort required, enabling testers to concentrate on more critical aspects of the testing process. Embracing automated testing enhances efficiency, accelerates the development lifecycle, and ensures consistent and reliable results across various environments and platforms.
In Drupal, there are primarily two types of testing that can be performed:
Unit Testing: Unit Testing involves testing individual pieces of code in isolation without relying on the Drupal core. It helps verify the correctness of specific functions or units of code.
Functional Testing: Functional Testing focuses on testing the overall functionality of Drupal code. It includes testing APIs, HTML pages, service classes, and other components to ensure that the entire system works as intended.
Following are examples of unit Testing
1. Testing a method that sorts an array in ascending order.
2. Testing a function that validates an email address.
3. Testing a class method that adds two numbers.
4. Testing a function that converts a string to uppercase.
5. Testing a method that checks if a given number is prime.
6. Testing a function that calculates the area of a circle.
7. Testing a method that parses a JSON string and returns an object.
8. Testing a function that finds the maximum value in an array.
Examples of Functional Testing in Drupal:
1. Testing user registration and login functionality to ensure users can create accounts and log in successfully.
2. Testing content creation and publishing to verify that content authors can create and publish articles, blog posts, or other content types.
3. Testing search functionality to ensure that search queries return relevant results.
4. Testing form submissions and validation to verify that user input is properly processed and validated.
5. Testing menu navigation to ensure that users can access different sections of the website using the menu links.
6. Testing API endpoints to ensure that external systems can interact with Drupal and retrieve data as expected.
7. Testing user permissions and access control to ensure that different user roles have the appropriate access to content and features.
8. Testing responsive design and cross-browser compatibility to ensure the website looks and functions correctly on various devices and browsers.
9. Testing multi-language support to verify that content can be translated and displayed correctly in different languages.
10. Testing integration with third-party modules or services to ensure seamless functionality and data exchange.
How to start PHP unit testing in Drupal?
Let’s start :
Initially, utilize Composer to install the essential core dependency and packages listed below.
composer require-dev drupal/core-dev
composer requires Weitzman/drupal-test-traits
2. Then configure the following phpunit.xml
This file is a configuration file for PHP Unit, a popular testing framework in PHP, specifically tailored for Drupal functional testing. Let’s break down the code:
1 PHPUnit Bootstrap and Options
bootstrap: Specifies the path to the bootstrap.php file from the "weitzman/drupal-test-traits" package. This package provides helpful test traits for Drupal functional testing.
2. PHP Configuration
memory limit: Sets the memory limit for running the tests to -1, indicating no memory limit.
SIMPLETEST_BASE_URL: Defines the base URL for the site being tested.
SIMPLETEST_DB: Specifies the database connection details for running tests. In this case, SQLite is used.
BROWSERTEST_OUTPUT_DIRECTORY: Specifies the directory where browser test output will be stored.
3. Custom Environment Variables
DTT_BASE_URL: Custom environment variable for the base URL.
DTT_API_URL: Custom environment variable for the API URL.
DTT_API_OPTIONS: Custom environment variable for API options, including socket timeout and DOM wait timeout.
4. Test Suites and Directories
<testsuites>: Configures the test suites for the Drupal custom modules.
<testsuite name="custom">: Defines a testsuite named "custom".
<directory>.././modules/custom</directory>: Specifies the directory where the custom module tests are located.
Then create the base class for functional testing
To run the test home
functional test function from the terminal, use the following approach:
💻 Let’s delve into various examples of unit and functional testing, taking them step by step.
1. Unit Testing
In the Support.php class, we have two methods called validFirstName and validLastName. Notably, these methods can be tested for their functionality independently of the Drupal core.
The code contains two PHP functions, validFirstName and validLastName, checking if a given input string represents a valid first or last name. They verify the length, absence of "@" character, and spaces. Returns TRUE if all checks pass, otherwise FALSE.
Here is the code for performing Unit Testing on the file mentioned above.
This code represents a unit test for the validFirstName()
function. It uses a testing framework (likely PHPUnit) to validate the behavior of the validFirstName()
method in the Support.php
class. The test method testFirstName()
contains multiple assertions to check various scenarios:
Assertion 1: It tests the case where the input name is “John,” and it expects the function to return TRUE.
Assertion 2: It tests the case where the input name is “John@Doe,” and it expects the function to return FALSE since it contains the "@" character.
Assertion 3: It tests the case where the input name is “Nico Wright,” and it expects the function to return FALSE because it contains a space.
Assertion 4: It tests the case where the input name is “Amy,” and it expects the function to return TRUE.
Assertion 5: It tests the case where the input name is “XY,” and it expects the function to return FALSE because it is too short.
The assertEquals()
method is used to compare the actual output of the validFirstName()
function with the
The data provider method lastNameProvider()
returns an array with multiple test cases and their corresponding expected outputs.
lastNameProvider()
:
1. This method serves as a data provider for the testLastName()
test method.
2. It returns an array of test cases, each represented as an associative array with two elements:
3. “expected”: The input value representing a last name.
4. “output”: The expected output (either TRUE
or FALSE
) when the validFirstName()
function is called with the corresponding input value.
testLastName($expected, $output)
:
1. This test method is marked with the @dataProvider
annotation, indicating that it will use the data provided by the lastNameProvider()
method to perform multiple test cases.
2. The method takes two parameters: $expected
and $output
, which represent the input value and the expected result, respectively, for each test case.
3. For each test case, it calls the validFirstName()
method of the Support
class with the given input value $expected
.
4. It then uses the assertEquals()
method to compare the actual output with the expected output $output
.
The test will pass if the actual output matches the expected output for each test case; otherwise, it will fail, indicating a potential issue with the validFirstName()
function.
The attachments provided below demonstrate how the testing appears when it fails.
2. Functional Testing
1. API Functional Testing
2. Service Class Testing
3. Web Page Testing
1. API Functional Testing
The code fetches Drupal student entities and filters them based on the “pass” or “fail” type and marks condition. It then returns a JSON response with student names and marks.
Here is the code for performing Functional Testing on the file mentioned above.
This code defines a test function named testHome
, likely written for testing a Drupal module or functionality related to student data. The test checks two scenarios: "pass" and "failed" students fetched from the Drupal endpoint "/web-ui/students/". It uses assertions to validate that the students' marks meet the expected criteria for pass and fail based on a threshold of 50. The test passes if all students' marks satisfy the respective conditions; otherwise, it fails.
2. Service Class Testing
This function checks if a given pizza node has a discount available based on the pizza type and the current time. If the pizza type is “onion” and the current time is between 12 PM and 2 PM, it returns TRUE; otherwise, it returns FALSE.
Here is the code for performing Functional Testing of the Service class on the file mentioned above.
Code Explanation: The setUpDateService
function in PHP creates a mocked Time
class object for testing. It converts the given date/time string into a Unix timestamp, sets an expectation that getCurrentTime()
method will return the timestamp, and stores the mocked object in a container for dependency injection.
testHasDiscountAvailable code is a test case for a pizza ordering system in Drupal. It checks if a pizza node with the “onion” type exists and if the current time is between 12 PM and 2 PM. The test expects the hasDiscountAvailable()
method to return TRUE
in this scenario. It ensures that the method correctly identifies the "onion" pizza type and the time slot for applying discounts. The test helps ensure the system's correctness by validating the discount logic and proper node creation.
3. Web Page Testing
Code Explanation
It first logs in as an administrator, visits the “/admin” page, and checks if the “Extend” link is present, asserting that it should be visible. Then, it logs out and visits the admin page again without any user role (guest/non-logged-in user) and checks if the “Extend” link is absent, asserting that it should not be visible. This test verifies that only administrators have access to the “Extend” functionality, ensuring the correct application of access permissions based on user roles.
Functional Testing of the Web HTML example.