Skip to content

Instantly share code, notes, and snippets.

@selvinortiz
Last active September 13, 2018 18:23
Show Gist options
  • Save selvinortiz/9605512 to your computer and use it in GitHub Desktop.
Save selvinortiz/9605512 to your computer and use it in GitHub Desktop.
Unit Testing for Craft Plugins

Unit Testing for Craft Plugins

Writing unit tests for your craft plugin has not been straight forward out of the gate but P&T is taking steps to fully integrate unit testing and have already added the basic necessities to do so.

Assumed Directory Structure


@craft = /path/to/site/craft
@craftTests = @craft/app/tests
@craftVendor = @craft/app/vendor
@craftPlugins = @craft/plugins
@pluginTestDir = @craft/plugins/yourplugin/tests

/path/to/site/craft
  - /app
    - /tests
    - /vendor
  - /plugins
    - plugin
      - tests

Other Assumptions

  • PHP 5.3.2+ is properly installed and can be called from the command line

Example Test

<?php
namespace Craft;

use \Mockery as m;

class PluginTest extends BaseTest
{
	protected $config;
	protected $service;

	public function setUp()
	{
		$this->config = m::mock('Craft\ConfigService');
		$this->config->shouldReceive('getIsInitialized')->andReturn(true);
		$this->config->shouldReceive('usePathInfo')->andReturn(true)->byDefault();

		$this->config->shouldReceive('get')->with('usePathInfo')->andReturn(true)->byDefault();
		$this->config->shouldReceive('get')->with('cpTrigger')->andReturn('admin')->byDefault();
		$this->config->shouldReceive('get')->with('pageTrigger')->andReturn('p')->byDefault();
		$this->config->shouldReceive('get')->with('actionTrigger')->andReturn('action')->byDefault();
		$this->config->shouldReceive('get')->with('translationDebugOutput')->andReturn(false)->byDefault();

		$this->config->shouldReceive('getLocalized')->with('loginPath')->andReturn('login')->byDefault();
		$this->config->shouldReceive('getLocalized')->with('logoutPath')->andReturn('logout')->byDefault();
		$this->config->shouldReceive('getLocalized')->with('setPasswordPath')->andReturn('setpassword')->byDefault();

		$this->config->shouldReceive('getCpLoginPath')->andReturn('login')->byDefault();
		$this->config->shouldReceive('getCpLogoutPath')->andReturn('logout')->byDefault();
		$this->config->shouldReceive('getCpSetPasswordPath')->andReturn('setpassword')->byDefault();
		$this->config->shouldReceive('getResourceTrigger')->andReturn('resource')->byDefault();

		$this->setComponent(craft(), 'config', $this->config);
		$this->setEnvironment();
		$this->loadServices();
	}

	public function testGetRequestIp()
	{
		$this->assertEquals($_SERVER['REMOTE_ADDR'], '127.0.0.1');
	}

	protected function setEnvironment()
	{
		$this->settings			= m::mock('Craft\Model');
		$_SERVER['REMOTE_ADDR']	= '127.0.0.1';
	}

	protected function loadServices()
	{
		require_once __DIR__ . '/../services/PluginService.php';

		$this->service = new PluginService();
	}

	protected function inspect($data)
	{
		fwrite(STDERR, print_r($data));
	}
}

Running PHPUnit

From Terminal

This is an example to run from the command line but do note that there are other ways to do it.

Full Command

/path/to/php -c /path/to/php.ini @craftVendor/phpunit/phpunit/phpunit.php --bootstrap @craftTests/bootstrap.php --configuration @craftTests/phpunit.xml @pluginTestDir

Step By Step Command

These commands should be executed as a single command with exactly one space between each step.

Invoke the PHP executable and pass along our php.ini

php -c /etc/php5/apache2/php.ini

Run PHPUnit through PHP

/path/to/site/craft/vendor/phpunit/phpunit/phpunit.php or which phpunit

Tell PHPUnit what bootstrap file to use

--bootstrap /path/to/site/craft/app/tests/bootstrap.php

Tell PHPUnit to use the configuration file provided by Craft

--configuration /path/to/site/craft/app/tests/phpunit.xml

Finally, tell PHPUnit where to find your plugin test directory

/path/to/site/craft/plugins/yourplugin/tests

Issues

The biggest issues I've come across during testing have to do with bootstrapping dependencies.

Some issues are really hard to diagnose and explain and in effort to keep this short... I figured that rather than explaining every single issue I've found, I'd just post what is currently working for me and other's I've helped and if you can't get things running just post a comment here and we can sort it out together.

Written By

Selvin Ortiz
Lead Developer
Barrel Strength Design

@johndwells
Copy link

There appears to be a typo in your example method loadServices(), the service name is PluginsService (double sS), had to fix the path in line 50 and then the instantiation at line 52.

@selvinortiz
Copy link
Author

Thanks for pointing out the typo John.

The sample test was a last minute thing and the point was to illustrate what you may write in your pluging so I think it's totally out of context and the paths were totally relying on your plugin files like services being present.

What I think I'll do is create a simple skeleton plugin an turn this gist into a full repo so that I can provide more context and a full walkthrough so that others can use as reference and contribute their findings in a more github like way!

I'll be reviewing/formalizing this tonight to make it easier to get started with.

Thanks for the feedback bro!

@putyourlightson
Copy link

thanks for creating this selvin.

another small typo: "/path/to/site/craft/vendor/phpunit/phpunit/phpunit.php" should read "/path/to/site/craft/app/vendor/phpunit/phpunit/phpunit.php"

@ryanbrookepayne
Copy link

Does this still work with the latest version of Craft? I'm not seeing any phpunit dependencies and I don't even see a tests directory in Craft. I have yet to successfully implement unit testing on Craft.

@selvinortiz
Copy link
Author

@ryanbrookepayne I'm so sorry, I just saw your comment, I didn't get a notification for it:(

Anyway, this is still how you would do it but unfortunately, Craft removed all of the tests from their recent builds, rendering these instructions worthless.

I'm reaching out to the P&T team and try to work with them on getting Unit testing stuff back.

@criticalmash
Copy link

@selvinortiz thanks for the plugin. I'm running into the same issues as @ryanbrookepayne. I've been able to install a copy of PHPUnit, but don't know where to find copies of the phpunit.xml or bootstrap.php files which I'm guessing are particular to Craft.

Even if any versions I have are not compatible with the latest Craft CMS release, at least I'd have a starting point I could work from. Do you know where I can find them?

I tried searching craftcms/cms for legacy files, but came up empty.

@criticalmash
Copy link

Just realized that BaseTest class is missing too. Perhaps I should start looking for an alternative testing setup.

@dnunez24
Copy link

Was struggling with the same issue, managed to find some historical context here: https://github.com/pixelandtonic/Craft-Release/blob/4c0e762ce014894a0f786d64afd67d0d95c25e73/app/tests/BaseTest.php

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment