Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Testing with PHPUnit

Testing with PHPUnit

Improved Error Handling and Styling

Workflow

  1. Given
  2. When
  3. Then

Usage

  • Run tests: phpunit aka vendor/bin/phpunit
  • Version: phpunit --version
  • Run testsuite only: phpunit --testsuite testsuitename
  • Run method only: phpunit --filter myTestMethod
  • Run group only: phpunit --group groupname
  • Generate coverage report: phpunit --coverage-html tests/coverage

PHPUnit & PhpStorm

External lib. include path (OS X & Mamp): /Applications/MAMP/Library/bin

PHPUnit & Laravel

PHPUnit & VVV

  • Defined version of PHPUnit: /usr/local/src/composer/composer.json
  • Update: sudo composer update

PHPUnit & WordPress

PHPUnit & WP-CLI


Notes

  • Every test-method has to be public and a method name starting with test or have the @test notation
  • Mock: Does not trigger the actual class, calls the interface instead (set expectation on what should happen)
  • Spy: Triggers the actual class, verify that it happened afterwards (reverse mock: do the action, verify that it happened)
  • Stubs: Returns any kind of hard-coded data (pre-defined values)
  • Dummies: Adheres to the contract just to run the test (methods will return NULL)
  • Factory: reusable element for test-related setup (for creating other objects)
  • Fixture: also a reusable element for test-related setup
  • A test-related method (called fixture) can be a private method not starting with test
  • Method visibility can be switched from protected to public via a proxy class
  • Skip tests via $this->markTestSkipped( 'Must be revisited.' )
  • Coverage report requires Xdebug extension
  • Tests coverage can be documented with @covers notation

Laravel Notes

  • Disable exception handling for a test: $this->withoutExceptionHandling()
  • Act as signed-in user: $this->actingAs(factory('App\User')->create());

Laravel Mockery Testing Helpers

Given App\Project class:

class Project {
	public function subscribeTo($name, $user) {
		//
	}
}

Mocking the object

// Create user
$user = factory(User::class)->create();

// Create mock
$this->mock(Project::class, function ($mock) use ($user) {
	$mock->shouldReceive()->subscribeTo('members', $user)->once();
});

// Perform action
$this->actingAs($user)->get('/endpoint');

Spying the object

// Create user
$user = factory(User::class)->create();

// Create spy
$spy = $this->spy(Project::class);

// Perform action
$this->actingAs($user)->get('/endpoint');

// Confirm action
$spy->shouldHaveReceived()->subscribeTo('members', $user);
# PHPUnit completion
source ~/phpunit.bash
# Bash-Completion script for PHPUnit
#
# Created by Henrique Moody <henriquemoody@gmail.com>
# https://gist.github.com/henriquemoody/5014805
#
_phpunit()
{
COMPREPLY=()
local cur="${COMP_WORDS[COMP_CWORD]}"
local prev="${COMP_WORDS[COMP_CWORD-1]}"
local opts="--coverage-clover --coverage-crap4j --coverage-html --coverage-php --coverage-text --coverage-xml --log-junit --log-tap --log-json --testdox-html --testdox-text --filter --testsuite --group --exclude-group --list-groups --test-suffix --report-useless-tests --strict-coverage --disallow-test-output --enforce-time-limit --disallow-todo-tests --process-isolation --no-globals-backup --static-backup --colors --columns --columns --stderr --stop-on-error --stop-on-failure --stop-on-risky --stop-on-skipped --stop-on-incomplete -v --verbose --debug --loader --repeat --tap --testdox --printer --bootstrap -c --configuration --no-configuration --include-path -d -h --help --version"
local diropts="--coverage-html|--coverage-xml|--include-path"
local nocompleteopts="--filter|--testsuite|--group|--exclude-group|--test-suffix|--loader|--repeat|--printer|-d|-h|--help|--version"
if [[ ${prev} =~ ${diropts} ]]; then
COMPREPLY=( $(compgen -d -- ${cur}) )
return 0
elif [[ ${prev} =~ ${nocompleteopts} ]]; then
return 0
elif [[ ${prev} = --columns ]]; then
COMPREPLY=( $(compgen -W "max" -- ${cur}) )
return 0
elif [[ ${prev} = --colors ]]; then
COMPREPLY=( $(compgen -W "auto never always" -- ${cur}) )
return 0
elif [[ "${cur}" == -* ]]; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
else
COMPREPLY=( $(compgen -f -- "${cur}") )
return 0
fi
}
complete -F _phpunit phpunit
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
bootstrap="./tests/bootstrap.php"
backupGlobals="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
>
<php>
<const name="PluginNamespace\Tests\DB_NAME" value="PLACEHOLDER"/>
<const name="PluginNamespace\Tests\DB_USER" value="PLACEHOLDER"/>
<const name="PluginNamespace\Tests\DB_PASSWORD" value="PLACEHOLDER"/>
<const name="PluginNamespace\Tests\DB_HOST" value="localhost"/>
<const name="PluginNamespace\Tests\DB_CHARSET" value="utf8"/>
<const name="PluginNamespace\Tests\DB_COLLATE" value=""/>
<const name="PluginNamespace\Tests\DB_TABLE_PREFIX" value="wp_"/>
</php>
<testsuites>
<testsuite name="Integration">
<directory suffix="Test.php" phpVersion="5.6.0" phpVersionOperator=">=">./tests/Integration</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-clover" target="build/logs/clover.xml"/>
</logging>
<filter>
<whitelist>
<directory>./src</directory>
<exclude>
<directory>./assets</directory>
<directory>./languages</directory>
<directory>./resources</directory>
<directory>./tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
printerClass="Codedungeon\PHPUnitPrettyResultPrinter\Printer">
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<listeners>
<listener class="NunoMaduro\Collision\Adapters\Phpunit\Listener" />
</listeners>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<php>
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<server name="MAIL_DRIVER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="DB_CONNECTION" value="sqlite"/>
<server name="DB_DATABASE" value=":memory:"/>
</php>
</phpunit>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment