Introduction to TDD and Its Application in WordPress
Test-Driven Development (TDD) is a software development approach where tests are written before the actual code. The process follows a cycle of writing a test, ensuring it fails, writing the minimal code to pass the test, and then refactoring the code while keeping all tests passing. TDD helps in creating more reliable and maintainable software by ensuring that code meets the desired requirements from the outset.
Using TDD in WordPress
Step 1: Setting Up the Testing Environment
To start with TDD in WordPress, you need a testing environment. Tools like PHPUnit and WP CLI make it easy to set up and run tests. Install PHPUnit and configure it for your WordPress project.
Step 2: Writing Tests
Begin by writing tests for your WordPress functionalities. For instance, if you are developing a custom plugin, write tests for each function or class method. Use assertions to verify the expected output.
class SampleTest extends WP_UnitTestCase {
public function test_sample_function() {
$result = sample_function();
$this->assertEquals('expected output', $result);
}}
Step 3: Writing Minimal Code
After writing the test, write the minimal code required to pass the test. Ensure that your code is just enough to make the test pass.
Step 4: Running Tests
Run your tests using PHPUnit to ensure they pass. If a test fails, refine your code until it passes.
phpunit
Step 5: Refactoring
Once all tests pass, refactor your code for optimization and readability, ensuring that tests still pass after each change.
Benefits of TDD in WordPress
- Enhanced Reliability: Ensures your code works as intended.
- Easier Refactoring: Facilitates safe code refactoring with confidence.
- Documentation: Tests serve as documentation for your code.
WordPress Coding Standards
The purpose of the WordPress Coding Standards is to create a baseline for collaboration and review within various aspects of the WordPress open source project and community, from core code to themes to plugins.
Why have coding standards?
Coding standards help avoid common coding errors, improve the readability of code, and simplify modification. They ensure that files within the project appear as if they were created by a single person.
Following the standards means anyone will be able to understand a section of code and modify it, if needed, without regard to when it was written or by whom.
Where do the coding standards not apply?
Third-party libraries are not subject to these standards, even when integrated with the primary project. This includes instances like WordPress core, where multiple third-party libraries are incorporated into its codebase.
PHP Coding Standards
These PHP coding standards are intended for the WordPress community as a whole. They are mandatory for WordPress Core and we encourage you to use them for your themes and plugins as well.
Opening and Closing PHP Tags:
When embedding multi-line PHP snippets within an HTML block, the PHP open and close tags must be on a line by themselves.
No Shorthand PHP Tags:
Important: Never use shorthand PHP start tags. Always use full PHP tags.
Correct:
<?php ... ?> <?php echo esc_html( $var ); ?>
Incorrect:
<? ... ?> <?= esc_html( $var ) ?>
Single and Double Quotes:
Use single and double quotes when appropriate. If you’re not evaluating anything in the string, use single quotes.
echo '<a href="/static/link" class="button button-primary">Link name</a>';
echo "<a href='{$escaped_link}'>text with a ' single quote</a>";
Writing include/require statements
Because include[_once] and require[_once] are language constructs, they do not need parentheses around the path, so those shouldn’t be used. There should only be one space between the path and the include/require keywords.
// Correct. require_once ABSPATH . 'file-name.php'; // Incorrect. include_once ( ABSPATH . 'file-name.php' ); require_once __DIR__ . '/file-name.php';
Naming Conventions
Use lowercase letters in variable, action/filter, and function names (never camelCase). Separate words via underscores. Don’t abbreviate variable names unnecessarily; let the code be unambiguous and self-documenting.
function some_name( $some_variable ) {}
Class, trait, interface and enum names should use capitalized words separated by underscores. Any acronyms should be all upper case.
class Walker_Category extends Walker {}
class WP_HTTP {}
interface Mailer_Interface {}
trait Forbid_Dynamic_Properties {}
enum Post_Status {}
Constants should be in all upper-case with underscores separating words:
define( 'DOING_AJAX', true );
Files should be named descriptively using lowercase letters. Hyphens should separate words.
my-plugin-name.php
Class file names should be based on the class name with class- prepended and the underscores in the class name replaced with hyphens, for example, WP_Error becomes:
class-wp-error.php
Files containing template tags in the wp-includes directory should have -template appended to the end of the name so that they are obvious.
general-template.php
Interpolation for Naming Dynamic Hooks
Dynamic hooks should be named using interpolation rather than concatenation for readability and discoverability purposes.
Dynamic hooks are hooks that include dynamic values in their tag name, e.g. {$new_status}_{$post->post_type} (publish_post).
Variables used in hook tags should be wrapped in curly braces { and }, with the complete outer tag name wrapped in double quotes. This is to ensure PHP can correctly parse the given variables’ types within the interpolated string.
do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );
Where possible, dynamic values in tag names should also be as succinct and to the point as possible. $user_id is much more self-documenting than, say, $this->id.
Whitespace
Space Usage
Always put spaces after commas, and on both sides of logical, arithmetic, comparison, string and assignment operators.
Indentation
Your indentation should always reflect logical structure. Use real tabs, not spaces, as this allows the most flexibility across clients.
Remove Trailing Spaces
Remove trailing whitespace at the end of each line. Omitting the closing PHP tag at the end of a file is preferred. If you use the tag, make sure you remove trailing whitespace.
Type declarations
Type declarations must have exactly one space before and after the type. The nullability operator (?) is regarded as part of the type declaration and there should be no space between this operator and the actual type. Class/interface/enum name based type declarations should use the case of the class/interface/enum name as declared, while the keyword-based type declarations should be lowercased.
// Correct.
function foo( Class_Name $parameter, callable $callable, int $number_of_things = 0 ) {
// Do something.
}
function bar(
Interface_Name&Concrete_Class $param_a,
string|int $param_b,
callable $param_c = 'default_callable'
): User|false {
// Do something.
}
// Incorrect.
function baz(Class_Name $param_a, String$param_b, CALLABLE $param_c ) : ? iterable {
// Do something.
}
- The scalar
bool,int,float, andstringtype declarations cannot be used until the minimum PHP version is PHP 7.0 or higher. - Return type declarations cannot be used until the minimum PHP version is PHP 7.0 or higher.
- Nullable type declarations cannot be used until the minimum PHP version is PHP 7.1 or higher.
- The
iterableandvoidtype declarations cannot be used until the minimum PHP version is PHP 7.1 or higher. Thevoidtype can only be used as a return type. - The
objecttype declaration cannot be used until the minimum PHP version is PHP 7.2 or higher. - Property type declarations cannot be used until the minimum PHP version is PHP 7.4 or higher.
static(return type only) cannot be used until the minimum PHP version is PHP 8.0 or higher.mixedtype cannot be used until the minimum PHP version is PHP 8.0 or higher. Take note that themixedtype includesnull, so cannot be made nullable.- Union types cannot be used until the minimum PHP version is PHP 8.0 or higher.
- Intersection types cannot be used until the minimum PHP version is PHP 8.1 or higher.
never(return type only) cannot be used until the minimum PHP version is PHP 8.1 or higher.- Disjunctive normal form types (combining union types and intersection types) cannot be used until the minimum PHP version is PHP 8.2 or higher.
Magic constants
The PHP native * magic constants, like CLASS and DIR, should be written in uppercase when used.
When using the ::class constant for class name resolution, the class keyword should be in lowercase and there should be no spaces around the :: operator.
// Correct. add_action( 'action_name', array( __CLASS__, 'method_name' ) ); add_action( 'action_name', array( My_Class::class, 'method_name' ) ); // Incorrect. require_once __dIr__ . '/relative-path/file-name.php'; add_action( 'action_name', array( My_Class :: CLASS, 'method_name' ) );
Spread operator …
When using the spread operator, there should be one space or a new line with the appropriate indentation before the spread operator.
// Correct.
function foo( &...$spread ) {
bar( ...$spread );
bar(
array( ...$foo ),
...array_values( $keyed_array )
);
}
// Incorrect.
function fool( & ... $spread ) {
bar(...
$spread );
bar(
[... $foo ],... array_values( $keyed_array )
);
}
The spread operator (or splat operator as it’s known in other languages) can be used for packing arguments in function declarations (variadic functions) and unpacking them in function calls as of PHP 5.6. Since PHP 7.4, the spread operator is also used for unpacking numerically-indexed arrays, with string-keyed array unpacking available since PHP 8.1.
When used in a function declaration, the spread operator can only be used with the last parameter.
Thank you for reading…
By Leaveitblank (Mayank Tripathi)