Brain-WP/BrainMonkey

Testing hooks from plugin factory fails

Closed this issue · 6 comments

I'm rewriting my plugin and trying to use patterns like factory and service locator like here: https://github.com/schlessera/wcbtn-2018-api (factory, plugin).

I have set up my testing, loaded everything using composer (I'm autoloading my classes using classmap), and when I run tests, I can confirm that the unit test is passing through the code properly.

For instance, I want to check the hooks defined in register method that looks like this:

  /**
   * Register the plugin with the WordPress system.
   *
   * @throws Exception\InvalidService If a service is not valid.
   */
  public function register() : void {
    add_action( 'plugins_loaded', [ $this, 'register_services' ] );
    add_action( 'init', [ $this, 'register_assets_handler' ] );
  }

I tried adding the print_r inside this method and I can see some output when I run

./vendor/bin/phpunit -c phpunit.xml.dist --no-coverage --colors=always"

My test looks like this:

<?php
/**
 * Class Plugin tests
 *
 * @package My_Plugin\Tests\Unit\Src
 */

use Brain\Monkey\Actions;

use My_Plugin\Tests\Init_Test_Case;

use My_Plugin\Core\Plugin_Factory;
use My_Plugin\Core\Plugin;

/**
 * Class that tests the Main plugin functionality.
 */
class Plugin_Factory_Test extends Init_Test_Case {

  public function setUp() {
    parent::setUp();

    Plugin_Factory::create()->register();
  }

  public function test_plugin_execution() {
    $this->assertTrue( has_action( 'plugins_loaded', 'My_Plugin\Core\Plugin->register_services()' ) );
    $this->assertTrue( has_action( 'init', 'My_Plugin\Core\Plugin->register_assets_handler()' ) );
  }
}

When the plugin is loaded the Plugin_Factory::create()->register(); method is called, so this is what I've put in my tests setUp method.

As I've said, this works, as print_r will show stuff in my terminal.

But I get

1) Plugin_Factory_Test::test_plugin_execution
Failed asserting that false is true.

/Users/denis/vagrant-local/www/personal/project/public_html/wp-content/plugins/my-plugin/tests/unit/src/test-plugin-factory.php:31

I even tried with

Actions\expectAdded( 'plugins_loaded' );
Actions\expectAdded( 'init' );

But that throws the following error:

There was 1 error:

1) Plugin_Factory_Test::test_plugin_execution
Mockery\Exception\InvalidCountException: Method add_action_plugins_loaded(<Any Arguments>) from Mockery_0 should be called
 at least 1 times but called 0 times.

/Users/denis/vagrant-local/www/personal/project/public_html/wp-content/plugins/my-plugin/vendor/mockery/mockery/library/Mockery/CountValidator/AtLeast.php:47
/Users/denis/vagrant-local/www/personal/project/public_html/wp-content/plugins/my-plugin/vendor/mockery/mockery/library/Mockery/Expectation.php:310
/Users/denis/vagrant-local/www/personal/project/public_html/wp-content/plugins/my-plugin/vendor/mockery/mockery/library/Mockery/ExpectationDirector.php:123
/Users/denis/vagrant-local/www/personal/project/public_html/wp-content/plugins/my-plugin/vendor/mockery/mockery/library/Mockery/Container.php:303
/Users/denis/vagrant-local/www/personal/project/public_html/wp-content/plugins/my-plugin/vendor/mockery/mockery/library/Mockery/Container.php:288
/Users/denis/vagrant-local/www/personal/project/public_html/wp-content/plugins/my-plugin/vendor/mockery/mockery/library/Mockery.php:204
/Users/denis/vagrant-local/www/personal/project/public_html/wp-content/plugins/my-plugin/vendor/brain/monkey/inc/api.php:38
/Users/denis/vagrant-local/www/personal/project/public_html/wp-content/plugins/my-plugin/tests/init-setup.php:28

Any idea why this doesn't want to work?

Before refactoring (wasn't using factory and other design patterns besides dependency injection), this worked (I had one issue opened before with rest_pre_serve_request iirc).

Hi @dingo-d what's in your Init_Test_Case?

Brain Monkey to work necessitates of some setup (see https://github.com/Brain-WP/BrainMonkey/blob/master/docs/wordpress-setup.md#setup-tests) if your base test case don't include the setup, Brain Monkey will not work.

The latest error you posted normally happens when Brain Monkey is not setup properly.

After that, I see you're adding expectations in a test for something that you do outside the test itself: you call Plugin_Factory::create()->register(); in the setUp method, but then check for has_action in the test_plugin_execution method...
This should work, but it really depends on how PHPUnit handle the call of setUp... so I can't guarantee it works now and will continue to work in future, because I don't control PHPUnit. If you really want to call code in your setUp method and you want to also add expectations for that code, I suggest to put the expectations in the same method that call the code.

But if what you are writing are unit tests, very likely you don't need to run register before each test, which means you could call it in the test_plugin_execution method only, that is where you add expectations for it...
...and if they are not unit tests, but e.g. integration tests... then probably you should consider not using Brain Monkey at all.

Oh, I forgot to post the init class

<?php
/**
 * Class Init tests
 *
 * @package My_Plugin\Tests
 */

namespace My_Plugin\Tests;

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

abstract class Init_Test_Case extends TestCase {
  /**
   * Setup method necessary for Brain Monkey to function
   */
  protected function setUp() {
    parent::setUp();
    Monkey\setUp();
    \WP_Mock::setUp();
  }

  /**
   * Teardown method necessary for Brain Monkey to function
   */
  protected function tearDown() {
    Monkey\tearDown();
    \WP_Mock::tearDown();
    parent::tearDown();
  }
}

I'm also using WP_Mock for mocking certain stuff. I used BrainMonkey before, and it's great for unit testing, but I'll need to rewrite the tests, as I'm rewriting the plugin rather drastically (structure, the business logic will remain the same).

when I used expectAdded I added the register part in the test method, like in the docs.

I see that in the md file you linked there is use MockeryPHPUnitIntegration; part added. Maybe I'm missing those. I was looking at the page and didn't notice this.

Not sure why this fails, but I've successfully mocked and tested other methods, and the hooks seem to be green (covered). 🤷‍♂️

Just a quick update. The init test case looks fine, just strange you're using both WP_Mock and Brain Monkey, as both of them cover same use cases. But I'll look better into the issue when back from vacations in january.

The WP_Mock is the remnant from old tests, where I had to figure out how to mock stuff (and in the process of writing tests I realized how tightly I coupled my code, and made my life miserable xD). I'll work on this more after the vacations as well to see if I missed anything 🙂

Thanks and enjoy the holidays!

It seems this is an incompatibility with WP_Mock, which is not really supported anymore, I even saw 10up code in the wild that use Brain Monkey.
For that, and for lack of activity I think we can close this.