A workshop with @thorstenfrommen
There are several things you might be able to test:
The process of evaluating a system or component during or at the end of the development process to determine whether it satisfies specified requirements. IEEE Std 610.12-1990
Unit testing is applying white-box testing techniques,
meaning close examination of procedural level of detail.
In order for this to work, the person designing the test is
required to have full knowledge of internals.
function answer() {
return '42';
}
In order to test if the function behaves as expected,
we have to know what the expectation is.
Possible units in code:
Logic is testable, and so are functions and classes.
Going even higher to namespaces, packages and so on is no good.
Define a unit as either logic, or function, or class.
function convert( $number ) {
if ( $number > 0 ) {
return $number * 2;
}
return $number / 2;
}
While logic might be testable, very often it is not testable as a unit.
⇒ A reasonable unit is either a function, or a class.
One of the most important and yet often overlooked aspects of unit testing.
Why? If a test fails, you cannot know what went wrong where and why.
If the only real code is the method under test,
you know it is the reason for a failing unit test.
function test_register_taxonomy() {
$tax = rand_str();
$this->assertFalse( taxonomy_exists( $tax ) );
register_taxonomy( $tax, 'post' );
$this->assertTrue( taxonomy_exists( $tax ) );
$this->assertFalse( is_taxonomy_hierarchical( $tax ) );
unset( $GLOBALS['wp_taxonomies'][ $tax ] );
}
This is not a unit test. But it has every right to exist.
How to test a unit in isolation?
⇒ Define dummy functions that you have absolute control over.
Take care of two things:
It is easier to create a mock object than to instantiate a real object.
Oftentimes, this real object has dependencies of its own, which means:
class Oracle {
public function answer() {
return '42';
}
}
class Oracle {
answer() {
return '42';
}
}
class OracleTest extends PHPUnit_Framework_TestCase {
public function test_return_expected_answer() {
$this->assertSame( '42', ( new Oracle() )->answer() );
}
}
test( ( assert ) => {
assert.equal( ( new Oracle() ).answer(), '42' );
assert.end();
} );
class FortuneTeller {
private $oracle;
public function __construct( Oracle $oracle ) {
$this->oracle = $oracle;
}
public function answer( $money = 0 ) {
return ( $money < 5 ) ? '' : $this->oracle->answer();
}
}
class FortuneTeller {
constructor( oracle ) {
this.oracle = oracle;
}
answer( money = 0 ) {
return ( money < 5 ) ? '' : this.oracle.answer();
}
}
class FortuneTellerTest extends PHPUnit_Framework_TestCase {
public function test_return_expected_answer() {
$answer = 'some answer here';
$oracle = $this->createConfiguredMock( Oracle::class, [
'answer' => $answer,
] );
$testee = new FortuneTeller( $oracle );
$this->assertSame( '', $testee->answer( 0 ) );
$this->assertSame( $answer, $testee->answer( 100 ) );
}
}
test( ( assert ) => {
const answer = 'some answer here';
const oracle = {
answer: () => answer
};
const testee = new Testee( oracle );
assert.equal( testee.answer( 0 ), '' );
assert.equal( testee.answer( 100 ), answer );
assert.end();
} );
class TranslatingOracle {
public function answer() {
return sprintf(
__( 'The answer is: %d.', 'some-text-domain-here' ),
mt_rand()
);
}
}
class TranslatingOracleTest extends PHPUnit_Framework_TestCase {
public function test_return_expected_answer() {
Patchwork\replace( '__', function () {
return '%d';
} );
$this->assertRegExp(
'/^\d+$/',
( new TranslatingOracle() )->answer()
);
}
}
class HookAwareOracle {
public function answer() {
do_action( 'give_answer' );
return (string) apply_filters( 'answer', '42' );
}
}
class HookAwareOracleTest extends PHPUnit_Framework_TestCase {
public function test_return_unfiltered_answer() {
$this->assertSame( '42', ( new HookAwareOracle() )->answer() );
$this->assertSame( 1, did_action( 'give_answer' ) );
$this->assertSame( 1, Monkey::filters()->applied( 'answer' ) );
}
}
class ThankfulOracle {
answer( money ) {
showNotice.note( `Thanks for "${Number( money )}", buddy.` );
return Math.random();
}
}
test( ( assert ) => {
global.showNotice = {
note: sinon.spy()
};
const money = 42;
assert.equal( typeof ( new ThankfulOracle() ).answer( money ),
'number' );
assert.equal( global.showNotice.note.callCount, 1 );
assert.equal( global.showNotice.note.calledWithMatch(
new RegExp( `"${Number( money )}"` ) ), true );
delete global.showNotice;
assert.end();
} );
class WhatClassTest extends PHPUnit_Framework_TestCase {
public function test_what_method_should_do_what() {
$actual = 'What is the actual result?';
$expected = 'What is the expected result?';
$this->assertSame( $expected, $actual, 'What should it do?' );
}
}
import test from 'tape';
test( 'What are you testing?', ( assert ) => {
const actual = 'What is the actual result?';
const expected = 'What is the expected result?';
assert.equal( actual, expected, 'What should it do?' );
assert.end();
} );
Unit testing...
Oh, and Inpsyde is hiring! :)
Pick whatever interests you the most: