Brain Monkey Tutorial: Simplified Unit Testing for WordPress

Unit testing in WordPress can be tricky due to its reliance on global functions and hooks. Brain Monkey simplifies this process by allowing you to mock WordPress functions, hooks, and filters easily. This tutorial will guide you through setting up a full WordPress project for Brain Monkey, along with detailed examples of unit testing real-world scenarios.

1. Prerequisites

Before starting, ensure you have the following installed:

  • PHP (7.4 or later recommended)

  • Composer

  • PHPUnit (installed via Composer)

  • A basic understanding of WordPress development

2. Setting Up the Project

Step 1: Create a WordPress Plugin Project

Create a folder for your plugin:

mkdir wp-brain-monkey-plugin
cd wp-brain-monkey-plugin

Step 2: Initialize Composer

Run the following command to create a composer.json file:

composer init

Follow the prompts and accept the defaults. Once complete, install the required dependencies.

Step 3: Install Brain Monkey and PHPUnit

Run:

composer require --dev brain/monkey phpunit/phpunit

This will install Brain Monkey and PHPUnit in the vendor directory.

Step 4: Set Up PHPUnit Configuration

Create a phpunit.xml file in the project root:

<?xml version="1.0"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd" bootstrap="tests/bootstrap.php">
    <testsuites>
        <testsuite name="Plugin Tests">
            <directory>./tests</directory>
        </testsuite>
    </testsuites>
</phpunit>

Step 5: Create a Test Bootstrap File

Create a tests/bootstrap.php file:

<?php

require_once __DIR__ . '/../vendor/autoload.php';

use Brain\Monkey;

// Set up Brain Monkey before each test
Brain\Monkey\setUp();

// Tear down Brain Monkey after each test
Brain\Monkey\tearDown();

Step 6: Create the Plugin File

Create my-plugin.php in the project root:

<?php
/*
Plugin Name: Brain Monkey Example Plugin
Description: A plugin to demonstrate Brain Monkey unit testing.
Version: 1.0
Author: Your Name
*/

function my_plugin_add_greeting($name) {
    return apply_filters('my_plugin_greeting', "Hello, $name!");
}

function my_plugin_register_shortcode() {
    add_shortcode('greeting', function ($atts) {
        $atts = shortcode_atts(['name' => 'Guest'], $atts);
        return my_plugin_add_greeting($atts['name']);
    });
}
add_action('init', 'my_plugin_register_shortcode');

3. Writing Unit Tests with Brain Monkey

Step 1: Create a Test Class

Create a tests/TestMyPlugin.php file:

<?php

use PHPUnit\Framework\TestCase;
use Brain\Monkey\Functions;

class TestMyPlugin extends TestCase {
    public function setUp(): void {
        parent::setUp();
        Brain\Monkey\setUp();
    }

    public function tearDown(): void {
        Brain\Monkey\tearDown();
        parent::tearDown();
    }

    // Your tests will go here
}

Step 2: Write Unit Tests

Test 1: Mocking apply_filters

public function test_my_plugin_add_greeting() {
    Functions\when('apply_filters')->justReturn('Hello, John!');

    $result = my_plugin_add_greeting('John');

    $this->assertEquals('Hello, John!', $result);
}

Test 2: Mocking a Hook (add_shortcode)

public function test_my_plugin_register_shortcode() {
    Functions\expect('add_shortcode')
        ->once()
        ->with('greeting', Functions\type('callable'));

    my_plugin_register_shortcode();
}

Test 3: Testing Shortcode Execution

public function test_shortcode_output() {
    Functions\when('apply_filters')->justReturn('Hello, Guest!');

    $output = my_plugin_add_greeting('Guest');

    $this->assertEquals('Hello, Guest!', $output);
}

Test 4: Mocking shortcode_atts

public function test_shortcode_atts() {
    Functions\when('shortcode_atts')->justReturn(['name' => 'John']);

    $atts = shortcode_atts(['name' => 'Guest'], ['name' => 'John']);

    $this->assertEquals(['name' => 'John'], $atts);
}

Test 5: Mocking add_action

public function test_my_plugin_init_hook() {
    Functions\expect('add_action')->once()->with('init', 'my_plugin_register_shortcode');

    my_plugin_register_shortcode();
}

Test 6: Testing Filters with Parameters

public function test_filter_with_parameters() {
    Functions\when('apply_filters')->alias(function ($tag, $value) {
        if ($tag === 'my_plugin_greeting') {
            return str_replace('Hello', 'Hi', $value);
        }
        return $value;
    });

    $result = my_plugin_add_greeting('John');

    $this->assertEquals('Hi, John!', $result);
}

Test 7: Testing Multiple Hooks

public function test_multiple_hooks() {
    Functions\expect('add_action')
        ->twice()
        ->withConsecutive(
            ['init', 'my_plugin_register_shortcode'],
            ['wp_footer', 'my_plugin_footer_callback']
        );

    add_action('init', 'my_plugin_register_shortcode');
    add_action('wp_footer', 'my_plugin_footer_callback');
}

4. Running the Tests

Run PHPUnit with the following command:

vendor/bin/phpunit

Sample Output:

PHPUnit 9.5.0 by Sebastian Bergmann and contributors.

.......                                                           7 / 7 (100%)

Time: 00:00.150, Memory: 6.00 MB

OK (7 tests, 7 assertions)

5. Conclusion

This tutorial demonstrates how Brain Monkey makes unit testing for WordPress plugins simple and effective. By mocking WordPress-specific functions and hooks, you can write robust, isolated tests for your plugins.

As you gain familiarity, you can extend this setup to include integration tests using tools like WP-Browser and PHPUnit. Happy testing!

0
Subscribe to my newsletter

Read articles from Junaid Bin Jaman directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Junaid Bin Jaman
Junaid Bin Jaman

Hello! I'm a software developer with over 6 years of experience, specializing in React and WordPress plugin development. My passion lies in crafting seamless, user-friendly web applications that not only meet but exceed client expectations. I thrive on solving complex problems and am always eager to embrace new challenges. Whether it's building robust WordPress plugins or dynamic React applications, I bring a blend of creativity and technical expertise to every project.