PHPUnit mocking WordPress function calls

A

Anonymous

Guest
Hi All,

I am building a simple WordPress plugin and I am looking to add unit tests using PHPUnit, I have the following class code:

Code:
<?php

namespace App;

class MyPlugin {

    public function __construct()
    {
        add_action('admin_enqueue_scripts', [$this, 'enqueueAdminScripts']);
        add_action('admin_menu', [$this, 'createAdminMenu']);
        add_action('admin_init', [$this, 'settings']);
    }

    public function enqueueAdminScripts()
    {
        // Code here
    }

    public function createAdminMenu()
    {
        // Code here
    }

    public function settings()
    {
        // Code here
    }

}

And this is my test file:

Code:
<?php

use App\MyPlugin;
use PHPUnit\Framework\TestCase;

class MyPlugin extends TestCase {

    protected $myPlugin;

    protected function setUp(): void
    {
        $this->myPlugin = new MyPlugin();
    }

    public function testRegister()
    {
        $this->assertInstanceOf('\App\MyPlugin', $this->myPlugin);
    }

}

However I am always getting the error
Code:
Error: Call to undefined function App\add_action()
when I run
Code:
vendor/bin/phpunit

What is the best way of mocking the add_action calls purely within PHPUnit without having to rely on a third party solution?

Any help with this would be greatly appreciated.
 
You need to include the entire wordpress to have the add_action what is wrong.
You should create an unit test where your methods will be tested without calling wordpress functions.
Wordpress is not good framework, so it is hard to write good tests for that. I suggest to you to create a new add_action function (in the App namespace) that do nothing except logging what you passed. You can also add some asserts to check that all necessary actions was added.

EDIT:
You can do other thing. Create a class in your plugin i.ex. WordpressFacade add use __callStatic method to call wordpress function. Then you can create another method to disable calling wordpress function and store information about called methods and their parameters. Then you will be able to simply switch the class to mock. The better solution (but also more complicated) is creating two classes, one for calling wordpress andone for mock and asserts, but then you should use the instance if these classes instead of calling static methods. Both solution have some advantages and disadvantages, so you need just consider what you need, but because you are using wordpress you should be ready for compromise.

I want to say one thing, because you care about the code quality, you should check other frameworks like laravel or cakephp (I hope you are working with better code than wordpress and it is just an "one time adventure"), becase architecture of wordpress is very outdated, so you can learn some bad patterns. Learning wordpress you are making step backward. You seems to be to good to use wordpress :)
 
<?php

use App\MyPlugin;
use PHPUnit\Framework\TestCase;

class MyPluginTest extends TestCase
{
public function testRegister()
{
// Create a mock object of MyPlugin
$myPluginMock = $this->getMockBuilder(MyPlugin::class)
->onlyMethods(['enqueueAdminScripts', 'createAdminMenu', 'settings'])
->getMock();

// Set expectations for the mocked methods
$myPluginMock->expects($this->once())->method('enqueueAdminScripts');
$myPluginMock->expects($this->once())->method('createAdminMenu');
$myPluginMock->expects($this->once())->method('settings');

// Call the constructor to simulate instantiation
$myPluginMock->__construct();

// Assert that the mock is an instance of MyPlugin
$this->assertInstanceOf(MyPlugin::class, $myPluginMock);
}
}

use the getMockBuilder() method to create a mock object of the MyPlugin class. specify the methods you want to mock using the onlyMethods() method.

then set expectations for the mocked methods using the expects() method, specifying the number of times you expect each method to be called.

After that, simulate the instantiation of MyPlugin by calling the constructor using $myPluginMock->__construct().

Finally, use the assertInstanceOf() method to assert that the mock object is an instance of the MyPlugin class.

By following this approach, you can effectively test your WordPress plugin code without relying on the actual WordPress functions.
 
Back
Top