Automated Testing in WordPress, Really?!

Preview:

DESCRIPTION

Did you know that WordPress has an automated test suite? It contains well over 1500 integration tests and growing. However one of the primary culprits of WordPress is in the quality of its plugins. Most plugins don't have an automated test suite you can run to verify all features are working as expected, and fail gracefully. In this talk, Ptah will introduce you to automated testing in WordPress using PHPUnit. We will cover concepts like unit testing, integration testing and end-to-end testing with examples in WordPress. You will leave the talk equipped with practical knowledge and ready to start adding an automated test suite to your plugins.

Citation preview

Automated Testing in

WordPress,Really?!

Rate this talk: https://joind.in/10115

#dc4d - Automated Testing in WordPress with @ptahdunbar

#dc4d - Automated Testing in WordPress with @ptahdunbar

Ptah (Pirate) Dunbar

● Started with WordPress and PHP in ‘05

● Contributing developer toWordPress, BuddyPress, bbPress

● Full stack Web Developer

● Architect at LiveNinja.com

● WPMIA co-organizer and SoFloPHP member

☠ Became Pirate Dunbar

#dc4d - Automated Testing in WordPress with @ptahdunbar

Ptah (Pirate) Dunbar

● Started with WordPress and PHP in ‘05

● Contributing developer toWordPress, BuddyPress, bbPress

● Full stack Web Developer

● Architect at LiveNinja.com

● WPMIA co-organizer and SoFloPHP member

☠ Became Pirate Dunbar

#dc4d - Automated Testing in WordPress with @ptahdunbar

● Started with WordPress and PHP in ‘05

● Contributing developer toWordPress, BuddyPress, bbPress

● Full stack Web Developer

● Architect at LiveNinja.com

● WPMIA co-organizer and SoFloPHP member

☠ Became Pirate Dunbar

Ptah (Pirate) Dunbar

#dc4d - Automated Testing in WordPress with @ptahdunbar

#dc4d - Automated Testing in WordPress with @ptahdunbar

● Understand automated testing concepts,ideas and best practices.

● Learn PHPUnit basics and the WordPress testsuite.

● Resources and homework

Agenda

In one hour

#dc4d - Automated Testing in WordPress with @ptahdunbar

WordPress powers

1 in 5 websites

source: http://w3techs.com/blog/entry/wordpress_powers_1_in_5_websites

#dc4d - Automated Testing in WordPress with @ptahdunbar

WordPress community

28,5102,177

source: http://w3techs.com/blog/entry/wordpress_powers_1_in_5_websites

#dc4d - Automated Testing in WordPress with @ptahdunbar

“The result is that a lot of the plugins are written in poor code and turn out to be poorly compatible with other plugins”

— Yoast

http://yoast.com/plugin-future/

Fail.

#dc4d - Automated Testing in WordPress with @ptahdunbar

● WP_DEBUG

● var_dump();

● print_r();

● error_log();

● debug_backtrace();

Manual Testing

Pull out the tools

#dc4d - Automated Testing in WordPress with @ptahdunbar

● WP_DEBUG

● var_dump();

● print_r();

● error_log();

● debug_backtrace();

Manual Testing

Pull out the tools

Ad-hoc & Temporary

#dc4d - Automated Testing in WordPress with @ptahdunbar

● WP_DEBUG

● var_dump();

● print_r();

● error_log();

● debug_backtrace();

Manual Testing

SLOW & Error Prone

Pull out the tools

#dc4d - Automated Testing in WordPress with @ptahdunbar

● WP_DEBUG

● var_dump();

● print_r();

● error_log();

● debug_backtrace();

Pull out the tools

Manual Testing

Doesn’t scale

#dc4d - Automated Testing in WordPress with @ptahdunbar

#dc4d - Automated Testing in WordPress with @ptahdunbar

A scripted process that invokes your app to test

features and compares the outcome with expected

results.

Automated Testing

#dc4d - Automated Testing in WordPress with @ptahdunbar

Persistent var_dumps();

Automated Testing

#dc4d - Automated Testing in WordPress with @ptahdunbar

Better than checking the logs

Automated Testing

#dc4d - Automated Testing in WordPress with @ptahdunbar

The Bigger Picture

Automated Testing

Continuous Integration

Continuous Delivery

TDD

BDD

Agile

Scrum

Continuous InspectionReleasing early, releasing often

Phingvagrant

#dc4d - Automated Testing in WordPress with @ptahdunbar

Getting started

Automate Testing

#dc4d - Automated Testing in WordPress with @ptahdunbar

There are so many

Frameworks

CHOOSE YOUR FRAMEWORK

#dc4d - Automated Testing in WordPress with @ptahdunbar

CHOOSE YOUR FRAMEWORK

PHPUnithttp://phpunit.de/manual/

Sebastian Bergmann

#dc4d - Automated Testing in WordPress with @ptahdunbar

vim composer.json && composer update

{ "require-dev": {

"phpunit/phpunit": "3.7.*",

"phpunit/phpunit-selenium" : "*",

}

}

http://getcomposer.org

#dc4d - Automated Testing in WordPress with @ptahdunbar

$>./vendor/bin/phpunit

PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

#dc4d - Automated Testing in WordPress with @ptahdunbar

PHPUnit

Terminology

#dc4d - Automated Testing in WordPress with @ptahdunbar

● Test CaseA set of conditions that you set up in order to assert expected outcome.

PHPUnit

Terminology

#dc4d - Automated Testing in WordPress with @ptahdunbar

PHPUnit

Terminology

● Test CaseA set of conditions that you set up in order to assert expected outcome.

● Test ClassA collection of test cases, extends PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

PHPUnit

Terminology

● Test CaseA set of conditions that you set up in order to assert expected outcome.

● Test ClassA collection of test cases, extends PHPUnit

● Test SuiteA collection of test classes

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?php// test classclass CalTest extends PHPUnit_Framework_TestCase{

// test case public function testAddReturnsSumOfTwoPositiveIntegers() { // assert stuff. }}

PHPUnit

TEST CLASS

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?php// test classclass CalTest extends PHPUnit_Framework_TestCase{

// test case public function testAddReturnsSumOfTwoPositiveIntegers() { // assert stuff. }}

PHPUnit

TEST CLASS

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/loader.phpincludes/

admin.phpapi.php…

phpunit.xmltests/

adminTest.phpApiTest.php…

PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/loader.phpincludes/

admin.phpfunctions.php…

phpunit.xmltests/

integration/…

acceptance/…

PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?xml version="1.0" encoding="UTF-8"?><phpunit bootstrap="vendor/autoload.php"> <testsuites> <testsuite name="tests"> <directory suffix="Test.php">tests/</directory> </testsuite> </testsuites></phpunit>

PHPUnit

phpunit.xml - configuration file for PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?xml version="1.0" encoding="UTF-8"?><phpunit bootstrap="vendor/autoload.php"> <testsuites> <testsuite name="tests"> <directory suffix="Test.php">tests/</directory> </testsuite> </testsuites></phpunit>

PHPUnit

phpunit.xml

Configure your test suite location

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?xml version="1.0" encoding="UTF-8"?><phpunit bootstrap="vendor/autoload.php"> <testsuites> <testsuite name="integration"> <directory suffix="Test.php">tests/integration</directory> </testsuite> <testsuite name="acceptance"> <directory suffix="Test.php">tests/acceptance</directory> </testsuite> </testsuites></phpunit>

PHPUnit

phpunit.xml

Configure your test suite location

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?xml version="1.0" encoding="UTF-8"?><phpunit bootstrap="vendor/autoload.php"> <testsuites> <testsuite name="tests"> <directory suffix="Test.php">tests/</directory> </testsuite> </testsuites></phpunit>

PHPUnit

phpunit.xml

Bootstrap file is included before any tests run

#dc4d - Automated Testing in WordPress with @ptahdunbar

Assertions

PHPUnit

Explicitly check expected outcomeagaisnt actual outcome.

#dc4d - Automated Testing in WordPress with @ptahdunbar

Assertions

PHPUnit

Explicitly check expected outcomeagaisnt actual outcome.

$this->assertTrue(condition);

#dc4d - Automated Testing in WordPress with @ptahdunbar

Arrange, Act, Assert

PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

function testThatItsTestingTime(){

}

1. A

2. A

3. A

PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

function testThatItsTestingTime(){

}

1. A

2. A

3. Assert (check for the expected behavior)

PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

function testThatItsTestingTime(){

}

1. A

2. Act (call the method/trigger the action)

3. Assert (check for the expected behavior)

PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

function testThatItsTestingTime(){

}

1. Arrange (the context/dependencies)

2. Act (call the method/trigger the action)

3. Assert (check for the expected behavior)

PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

Example

PHPUnit

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

// Act

// Assert

}}

PHPUnit

plugin/tests/unit/calTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

// Act

// Assert

}}

PHPUnit

plugin/tests/unit/calTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

// Act

// Assert $this->assertEquals(3, $result);

}}

PHPUnit

plugin/tests/unit/calTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

// Act $result = $calculator->add(1,2);

// Assert $this->assertEquals(3, $result);

}}

PHPUnit

plugin/tests/unit/calTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

$calculator = new Calculator();

// Act $result = $calculator->add(1,2);

// Assert $this->assertEquals(3, $result);

}}

PHPUnit

plugin/tests/unit/calTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

$calculator = new Calculator();

// Act $result = $calculator->add(1,2);

// Assert $this->assertEquals(3, $result);

}}

PHPUnit

plugin/tests/unit/calTest.php

./vendor/bin/phpunit

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

$calculator = new Calculator();

// Act $result = $calculator->add(1,2);

// Assert $this->assertEquals(3, $result);

}}

PHPUnit

plugin/tests/unit/calTest.php

Time: 148ms, Memory: 2.75Mb

OK: (1 test, 1 assertions)

./vendor/bin/phpunit

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

$calculator = new Calculator();

// Act $result = $calculator->add(1,2);

// Assert $this->assertEquals(3, $result);

}}

PHPUnit

plugin/tests/unit/calTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

$calculator = new Calculator();

// Act $result = $calculator->add(2,2);

// Assert $this->assertEquals(3, $result);

}}

PHPUnit

plugin/tests/unit/calTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

$calculator = new Calculator();

// Act $result = $calculator->add(2,2);

// Assert $this->assertEquals(3, $result);

}}

PHPUnit

plugin/tests/unit/calTest.php

./vendor/bin/phpunit

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass CalTest extends PHPUnit_Framework_TestCase{ public function testAddReturnsSumOfTwoPositiveIntegers() { // Arrange

$calculator = new Calculator();

// Act $result = $calculator->add(2,2);

// Assert $this->assertEquals(3, $result);

}}

PHPUnit

plugin/tests/unit/calTest.php

./vendor/bin/phpunit

Failed asserting that 4 equals 3

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange

// Act

// Assert

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange

// Act

// Assert$this->assertTrue($user instanceof ‘\LiveNinja\User\Entity’);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange

// Act$user = $service->persist($validUserdata);

// Assert$this->assertTrue($user instanceof ‘\LiveNinja\User\Entity’);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertTrue($user instanceof ‘\LiveNinja\User\Entity’);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertTrue($user instanceof ‘\LiveNinja\User\Entity’);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

./vendor/bin/phpunit

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertTrue($user instanceof ‘\LiveNinja\User\Entity’);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

./vendor/bin/phpunit

Time: 248ms, Memory: 1.95Mb

OK: (1 test, 1 assertions)

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertTrue($user instanceof ‘\LiveNinja\User\Entity’);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertTrue($user instanceof ‘\LiveRacoons\User\Entity’);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertTrue($user instanceof ‘\LiveRacoons\User\Entity’);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

./vendor/bin/phpunit

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertTrue($user instanceof ‘\LiveRacoons\User\Entity’);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

Failed asserting that false equals true

./vendor/bin/phpunit

#dc4d - Automated Testing in WordPress with @ptahdunbar

ASSERTIONSAppendix: http://phpunit.de/manual/3.7/en/appendixes.assertions.html

PHPUnit

Use the most specific assertion possible

● assertTrue();

● assertEquals();

● assertContains();

● assertGreaterThan();

● assertNotNull();

● assertFalse();

● assertNotEquals();

● assertContainsOnly();

● assertLessThan();

● assertSame();

#dc4d - Automated Testing in WordPress with @ptahdunbar

PHPUnit

There was 1 failure:

1) Tests_Basic::test_readmereadme.html's version needs to be updated to 3.9.Failed asserting that '3.8' matches expected '3.9'.

/private/tmp/wordpress-tests/tests/phpunit/tests/basic.php:29

FAIL

#dc4d - Automated Testing in WordPress with @ptahdunbar

PHPUnit

There was 1 failure:

1) Tests_User_Author::test_get_the_authorFailed asserting that two objects are equal.--- Expected+++ Actual@@ @@ WP_User Object ( 'data' => stdClass Object (- 'ID' => '3'- 'user_login' => 'User 1'- 'user_pass' => '$P$BpIqOzMNRGZNy9qxKL/3cCDCMe85o2.'- 'user_nicename' => 'user-1'- 'user_email' => 'user_2@example.org'+ 'ID' => '2'+ 'user_login' => 'test_author'+ 'user_pass' => '$P$BUdMebxEjJ23.6LbH9ujvVUFBsUuZv/'+ 'user_nicename' => 'test_author'+ 'user_email' => 'user_1@example.org' 'user_url' => '' 'user_registered' => '2013-12-20 15:31:01' 'user_activation_key' => '' 'user_status' => '0'- 'display_name' => 'User 1'+ 'display_name' => 'test_author' )- 'ID' => 3+ 'ID' => 2 'caps' => Array (- 'subscriber' => true+ 'author' => true ) 'cap_key' => 'wptests_capabilities' 'roles' => Array (- 0 => 'subscriber'+ 0 => 'author' ) 'allcaps' => Array ( 'read' => true 'level_0' => true- 'subscriber' => true+ 'upload_files' => true+ 'edit_posts' => true+ 'edit_published_posts' => true+ 'publish_posts' => true+ 'level_2' => true+ 'level_1' => true+ 'delete_posts' => true+ 'delete_published_posts' => true+ 'author' => true ) 'filter' => null )

/private/tmp/wordpress-tests/tests/phpunit/tests/user/author.php:50

FAIL

#dc4d - Automated Testing in WordPress with @ptahdunbar

PHPUnit

There was 1 failure:

1) Tests_User_Author::test_get_the_authorFailed asserting that two objects are equal.--- Expected+++ Actual@@ @@ WP_User Object ( 'data' => stdClass Object (- 'ID' => '3'- 'user_login' => 'User 1'- 'user_pass' => '$P$BpIqOzMNRGZNy9qxKL/3cCDCMe85o2.'- 'user_nicename' => 'user-1'- 'user_email' => 'user_2@example.org'+ 'ID' => '2'+ 'user_login' => 'test_author'+ 'user_pass' => '$P$BUdMebxEjJ23.6LbH9ujvVUFBsUuZv/'+ 'user_nicename' => 'test_author'+ 'user_email' => 'user_1@example.org' 'user_url' => '' 'user_registered' => '2013-12-20 15:31:01' 'user_activation_key' => '' 'user_status' => '0'- 'display_name' => 'User 1'+ 'display_name' => 'test_author' )- 'ID' => 3+ 'ID' => 2 'caps' => Array (- 'subscriber' => true+ 'author' => true ) 'cap_key' => 'wptests_capabilities' 'roles' => Array (- 0 => 'subscriber'+ 0 => 'author' ) 'allcaps' => Array ( 'read' => true 'level_0' => true- 'subscriber' => true+ 'upload_files' => true+ 'edit_posts' => true+ 'edit_published_posts' => true+ 'publish_posts' => true+ 'level_2' => true+ 'level_1' => true+ 'delete_posts' => true+ 'delete_published_posts' => true+ 'author' => true ) 'filter' => null )

/private/tmp/wordpress-tests/tests/phpunit/tests/user/author.php:50

FAIL

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertTrue($user instanceof ‘\LiveRacoon\User\Entity’);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertInstanceOf(‘\LiveNinja\User\Entity’, $user);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertInstanceOf(‘\LiveNinja\User\Entity’, $user);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

./vendor/bin/phpunit

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithValidUserdataReturnsUserObject() {

// Arrange$service = new \LiveNinja\User\Service;$validUserdata = [...];

// Act$user = $service->persist($validUserdata);

// Assert$this->assertInstanceOf(‘\LiveNinja\User\Entity’, $user);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

./vendor/bin/phpunit

Time: 148ms, Memory: 2.75Mb

OK: (1 test, 1 assertions)

#dc4d - Automated Testing in WordPress with @ptahdunbar

<?phpclass UserServiceTest extends PHPUnit_Framework_TestCase{ public function testPersistWithInvalidUserdataReturnsWPError() {

// Arrange$service = new \LiveNinja\User\Service;$invalidUserdata = [];

// Act$user = $service->persist($invalidUserdata);

// Assert$this->assertInstanceOf(‘WP_Error’, $user);

}

//…}

PHPUnit

plugin/tests/unit/LiveNinja/User/ServiceTest.php

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

WordPress with Testshttp://develop.svn.wordpress.org/trunk/

1858 Tests, 8611 Assertions, 2.59 minutes

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

#dc4d - Automated Testing in WordPress with @ptahdunbar

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

Getting started

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

WordPress Testsuite

<?xml version="1.0" encoding="UTF-8"?><phpunit bootstrap="tests/bootstrap-wp.php"> <testsuites> <testsuite name="tests"> <directory suffix="Test.php">tests/</directory> </testsuite> </testsuites></phpunit>

#dc4d - Automated Testing in WordPress with @ptahdunbar

WordPress Testsuite

<?xml version="1.0" encoding="UTF-8"?><phpunit bootstrap="tests/bootstrap-wp.php"> <testsuites> <testsuite name="tests"> <directory suffix="Test.php">tests/</directory> </testsuite>

<testsuite name="integration"> <directory suffix="Test.php">integration/</directory> </testsuite> </testsuites></phpunit>

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/PluginTest.php

<?phpclass PluginTest extends PHPUnit_Framework_TestCase{ // test cases...}

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/PluginTest.php

<?phpclass PluginTest extends WP_UnitTestCase{ // test cases...}

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

$>./vendor/bin/phpunit

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

#dc4d - Automated Testing in WordPress with @ptahdunbar

Run Testsinside of an isolated

WordPress Environment

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

ConfigureWordPressOptions

$GLOBALS['wp_tests_options'] = ['active_plugins' => [

'hello.php',...

],'current_theme' => 'kubrick',...

];

bootstrap.php

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

ConfigureWordPress

Includesfunction __muplugins_loaded(){

// code and stuff.require_once 'env-debug.php';

}tests_add_filter('muplugins_loaded', '__muplugins_loaded');

bootstrap.php

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

● Navigate to site URL (Updates globals)$this->get_url($url);

● Test WP_Query for Conditionals (is_page, is_single, is_404)$this->assertQueryTrue($arg1, $arg2, ...);

● Test for Errors$this->assertWPError($thing);

● Genereate WordPress data fixtures$this->factory->post->create_and_get();

$this->factory->comment->create_post_comments($pid, 100);

$this->factory->user->create_many(5);

$this->factory->blog->create();

and more…

WordPress Testsuite

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

// test casesfunction testRedirectForDateBasedPermalinks(){

// Arrange

// Act

// Assert

}}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

// test casesfunction testRedirectForDateBasedPermalinks(){

// Arrange

// Act

// Assert$this->assertQueryTrue( 'is_404' );

}}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

// test casesfunction testRedirectForDateBasedPermalinks(){

// Arrange$customWP = new WPCustomization;$this->factory->post->create(['post_date' => '2007-09-04 00:00:00']);

// Act$customWP->deprecate_unused_pages();$this->go_to('/2007/');

// Assert$this->assertQueryTrue( 'is_404' );

}}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

// test casesfunction testRedirectForDateBasedPermalinks(){

// Arrange$customWP = new WPCustomization;$this->factory->post->create(['post_date' => '2007-09-04 00:00:00']);

// Act$customWP->deprecate_unused_pages();$this->go_to('/2007/');

// Assert$this->assertQueryTrue( 'is_404' );

}}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

// test casesfunction testRedirectForDateBasedPermalinks(){

// Arrange$customWP = new WPCustomization;$this->factory->post->create(['post_date' => '2007-09-04 00:00:00']);

// Act$customWP->deprecate_unused_pages();$this->go_to('/2007/');

// Assert$this->assertQueryTrue( 'is_404' );

}}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

// test casesfunction testRedirectForDateBasedPermalinks(){

// Arrange$customWP = new WPCustomization;$this->factory->post->create(['post_date' => '2007-09-04 00:00:00']);

// Act$customWP->deprecate_unused_pages();$this->go_to('/2007/');

// Assert$this->assertQueryTrue( 'is_404' );

}}

./vendor/bin/phpunit

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

// test casesfunction testRedirectForDateBasedPermalinks(){

// Arrange$customWP = new WPCustomization;$this->factory->post->create(['post_date' => '2007-09-04 00:00:00']);

// Act$customWP->deprecate_unused_pages();$this->go_to('/2007/');

// Assert$this->assertQueryTrue( 'is_404' );

}}

./vendor/bin/phpunit

Time: 148ms, Memory: 2.75Mb

OK: (1 test, 1 assertions)

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

/** * @dataProvider getRequiredPlugins */function testAllRequiredPluginsAreActive($plugin){

// Assert$this->assertTrue( is_plugin_active($plugin),

sprintf('%s is not activated.', $plugin) );}

function getRequiredPlugins(){

return [[‘hello.php’],

];}

}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

/** * @dataProvider getRequiredPlugins */function testAllRequiredPluginsAreActive($plugin){

// Assert$this->assertTrue( is_plugin_active($plugin),

sprintf('%s is not activated.', $plugin) );}

function getRequiredPlugins(){

return [[‘hello.php’],

];}

}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

/** * @dataProvider getRequiredPlugins */function testAllRequiredPluginsAreActive($plugin){

// Assert$this->assertTrue( is_plugin_active($plugin),

sprintf('%s is not activated.', $plugin) );}

function getRequiredPlugins(){

return [[‘hello.php’],

];}

}

./vendor/bin/phpunit

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

/** * @dataProvider getRequiredPlugins */function testAllRequiredPluginsAreActive($plugin){

// Assert$this->assertTrue( is_plugin_active($plugin),

sprintf('%s is not activated.', $plugin) );}

function getRequiredPlugins(){

return [[‘hello.php’],

];}

}

./vendor/bin/phpunit

Time: 148ms, Memory: 2.75Mb

OK: (1 test, 1 assertions)

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

/** * @dataProvider getWPOptions */function testWPOptionSettingsAreConfigured($option_name, $option_value){

// Assert$this->assertSame($option_value, get_option($option_name));

}

function getWPOptions(){

return [[‘home’, ‘http://example.org/wp/’],[‘siteurl’, ‘http://example.org/’],

];}

}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

/** * @dataProvider getWPOptions */function testWPOptionSettingsAreConfigured($option_name, $option_value){

// Assert$this->assertSame($option_value, get_option($option_name));

}

function getWPOptions(){

return [[‘home’, ‘http://example.org/wp/’],[‘siteurl’, ‘http://example.org/’],

];}

}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

/** * @dataProvider getWPOptions */function testWPOptionSettingsAreConfigured($option_name, $option_value){

// Assert$this->assertSame($option_value, get_option($option_name));

}

function getWPOptions(){

return [[‘home’, ‘http://example.org/wp/’],[‘siteurl’, ‘http://example.org/’],

];}

}

./vendor/bin/phpunit

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/integration/WPCustomizationTest.php

WordPress Testsuite

<?phpclass WPCustomizationTest extends WP_UnitTestCase{

/** * @dataProvider getWPOptions */function testWPOptionSettingsAreConfigured($option_name, $option_value){

// Assert$this->assertSame($option_value, get_option($option_name));

}

function getWPOptions(){

return [[‘home’, ‘http://example.org/wp/’],[‘siteurl’, ‘http://example.org/’],

];}

}

./vendor/bin/phpunit

Time: 148ms, Memory: 2.75Mb

OK: (1 test, 1 assertions)

http://www.seleniumhq.org/

#dc4d - Automated Testing in WordPress with @ptahdunbar

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/acceptance/ConnectTest.php

Acceptance Testing

<?phpclass ConnectTest extends PHPUnit_Framework_TestCase{ protected function setUp() { }

public function testUserCanLogInViaTwitter() { }}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/acceptance/ConnectTest.php

Acceptance Testing

<?phpclass ConnectTest extends PHPUnit_Extensions_Selenium2TestCase{ protected function setUp() { }

public function testUserCanLogInViaTwitter() { }}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/acceptance/ConnectTest.php

Acceptance Testing

<?phpclass ConnectTest extends PHPUnit_Extensions_Selenium2TestCase{ protected function setUp() { $this->setBrowser("*chrome"); $this->setBrowserUrl("https://wpss.dev/"); }

public function testUserCanLogInViaTwitter() { }}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/acceptance/ConnectTest.php

Acceptance Testing

<?phpclass ConnectTest extends PHPUnit_Extensions_Selenium2TestCase{ protected function setUp() { $this->setBrowser("*chrome"); $this->setBrowserUrl("https://wpss.dev/"); }

public function testUserCanLogInViaTwitter() { $this->open("/");

}}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/acceptance/ConnectTest.php

Acceptance Testing

<?phpclass ConnectTest extends PHPUnit_Extensions_Selenium2TestCase{ protected function setUp() { $this->setBrowser("*chrome"); $this->setBrowserUrl("https://wpss.dev/"); }

public function testUserCanLogInViaTwitter() { $this->open("/"); $this->click("link=Log in"); $this->waitForPageToLoad("30000");

}}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/acceptance/ConnectTest.php

Acceptance Testing

<?phpclass ConnectTest extends PHPUnit_Extensions_Selenium2TestCase{ protected function setUp() { $this->setBrowser("*chrome"); $this->setBrowserUrl("https://wpss.dev/"); }

public function testUserCanLogInViaTwitter() { $this->open("/"); $this->click("link=Log in"); $this->waitForPageToLoad("30000"); $this->click("css=img[alt=\"Twitter\"]"); $this->waitForPageToLoad("30000");

}}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/acceptance/ConnectTest.php

Acceptance Testing

<?phpclass ConnectTest extends PHPUnit_Extensions_Selenium2TestCase{ protected function setUp() { $this->setBrowser("*chrome"); $this->setBrowserUrl("https://wpss.dev/"); }

public function testUserCanLogInViaTwitter() { $this->open("/"); $this->click("link=Log in"); $this->waitForPageToLoad("30000"); $this->click("css=img[alt=\"Twitter\"]"); $this->waitForPageToLoad("30000"); $this->assertContains( ‘dashboard’, $this->title() ); }}

#dc4d - Automated Testing in WordPress with @ptahdunbar

plugin/tests/acceptance/ConnectTest.php

Acceptance Testing

<?phpclass ConnectTest extends PHPUnit_Extensions_Selenium2TestCase{ protected function setUp() { $this->setBrowser("*chrome"); $this->setBrowserUrl("https://wpss.dev/"); }

public function testUserCanLogInViaTwitter() { $this->open("/"); $this->click("link=Log in"); $this->waitForPageToLoad("30000"); $this->click("css=img[alt=\"Twitter\"]"); $this->waitForPageToLoad("30000"); $this->assertContains( ‘dashboard’, $this->title() ); }}

Time: 148ms, Memory: 2.75Mb

OK: (1 test, 1 assertions)

#dc4d - Automated Testing in WordPress with @ptahdunbar

Acceptance

Selenium IDE Plugin

● Visually navigate throughout your site and generate a PHPUnittest case.

● Download Extension○ http://www.seleniumhq.

org/projects/ide/

● Download PHPUnit Formatter○ https://addons.mozilla.org/en-

US/firefox/addon/selenium-ide-php-formatters/

#dc4d - Automated Testing in WordPress with @ptahdunbar

Acceptance

Selenium IDE Plugin

● Visually navigate throughout your site and generate a PHPUnittest case.

● Download Extension○ http://www.seleniumhq.

org/projects/ide/

● Download PHPUnit Formatter○ https://addons.mozilla.org/en-

US/firefox/addon/selenium-ide-php-formatters/

#dc4d - Automated Testing in WordPress with @ptahdunbar

How can we be confident that our tests

cover everything?

#dc4d - Automated Testing in WordPress with @ptahdunbar

Testing boundaries

#dc4d - Automated Testing in WordPress with @ptahdunbar

● (User) Acceptance Testing

○ Verify that all features are done done.

○ Black-box testing, no knowledge of internals.

Testing boundaries

#dc4d - Automated Testing in WordPress with @ptahdunbar

● (User) Acceptance Testing

○ Verify that all features are done done.

○ Black-box testing, no knowledge of internals.

● Integration Testing

○ Test WordPress settings/configuration;

○ Compatibility between plugins and themes.

Testing boundaries

#dc4d - Automated Testing in WordPress with @ptahdunbar

● (User) Acceptance Testing

○ Verify that all features are done done.

○ Black-box testing, no knowledge of internals.

● Integration Testing

○ Test WordPress settings/configuration,

○ Compatibility between plugins and themes

● Unit Testing

○ Test class methods and functions in isolation, zero dependencies

○ Does one “behavoir”

Testing boundaries

#dc4d - Automated Testing in WordPress with @ptahdunbar

● (User) Acceptance Testing

Verify that all features are done done,

black-box testing, no knowledge of

internals

● Integration Testing

Test WordPress settings/configuration,

compatibility between plugins and

themes

● Unit Testing

Test class methods and functions in

isolation, zero dependencies,

does one “behavoir”.

Testing boundaries

AcceptanceTesting

Integration Testing

Unit Testing

#dc4d - Automated Testing in WordPress with @ptahdunbar

● (User) Acceptance Testing

Verify that all features are done done,

black-box testing, no knowledge of

internals

● Integration Testing

Test WordPress settings/configuration,

compatibility between plugins and

themes

● Unit Testing

Test class methods and functions in

isolation, zero dependencies,

does one “behavoir”.

Testing boundaries

AcceptanceTesting

Integration Testing

Unit Testing

#dc4d - Automated Testing in WordPress with @ptahdunbar

● (User) Acceptance Testing

Verify that all features are done done,

black-box testing, no knowledge of

internals

● Integration Testing

Test WordPress settings/configuration,

compatibility between plugins and

themes

● Unit Testing

Test class methods and functions in

isolation, zero dependencies,

does one “behavoir”.

Testing boundaries

Integration Testing

Unit Testing

AcceptanceTesting

#ATWP // Automated Testing in WordPress // @ptahdunbar

What to tests?

● Test plugin works in various WordPress setups

○ Does it work under multisite?

○ What about a custom content directory?

● Test all code paths in functions and methods

● Test compatiblity between most popular plugins

● Test that default pages exists

#ATWP // Automated Testing in WordPress // @ptahdunbar

What to tests?

● Test for theme support

● Test that post formats contain property elements

● Test any required assets that need to be loaded in

templates

● Test for required elements on a page

● Verify search results template displays search term

● Verify SEO meta tags

1. WordPress APIs

#ATWP // Automated Testing in WordPress // @ptahdunbar

What to not tests?

#ATWP // Automated Testing in WordPress // @ptahdunbar

What to not tests?

1. WordPress APIs

2. PHP language features

#ATWP // Automated Testing in WordPress // @ptahdunbar

What to not tests?

1. WordPress APIs

2. PHP language features

3. Third party vendor code

Getting into the groove

#ATWP // Automated Testing in WordPress // @ptahdunbar

#ATWP // Automated Testing in WordPress // @ptahdunbar

Getting into the groove

● Build out templates

● Build out templates○ Create HTML/CSS

#ATWP // Automated Testing in WordPress // @ptahdunbar

Getting into the groove

#ATWP // Automated Testing in WordPress // @ptahdunbar

Getting into the groove

● Build out templates○ Create HTML/CSS○ Identify dynamic elements and their data

structure

#ATWP // Automated Testing in WordPress // @ptahdunbar

Getting into the groove

● Build out templates○ Create HTML/CSS○ Identify dynamic elements and their data

structure○ Label them and fill them with dummy data

#ATWP // Automated Testing in WordPress // @ptahdunbar

Getting into the groove

○ Verbally state your trying to do

#ATWP // Automated Testing in WordPress // @ptahdunbar

Getting into the groove

○ Verbally state your trying to do

○ Verbally explain what the code does

#ATWP // Automated Testing in WordPress // @ptahdunbar

Getting into the groove

○ Verbally state your trying to do

○ Verbally explain what the code does

○ Do this alone or with a fellow dev :)

What’s Next?

#dc4d - Automated Testing in WordPress with @ptahdunbar

● Download WP Skeleton Family

○ https://github.com/ptahdunbar/wp-skeleton-site

○ https://github.com/ptahdunbar/wp-skeleton-plugin

○ https://github.com/ptahdunbar/wp-skeleton-theme

Get started

“A Walking Skeleton is a tiny implementation of the thinnest possible slice of real functionality that we can automatically

build, deploy and test end-to-end.”

#dc4d - Automated Testing in WordPress with @ptahdunbar

● Art of Unit Testing (.NET)

○ https://leanpub.com/u/royosherove

○ Udemy Five day course

● #GOOS Book (Java)

● XUnit Test Patterns (Java)

● Grumpy Books (PHP)

○ https://leanpub.com/u/chartjes

● Misko Hevery

Resources

#dc4d - Automated Testing in WordPress with @ptahdunbar

● Learn moar PHPUnit features

○ data providers,

○ mocks and stubs

○ wordpress testsuite

● Goal: Write at least 100 assertions!

Homework!

TODO

#dc4d - Automated Testing in WordPress with @ptahdunbar

Automated Testing

#dc4d - Automated Testing in WordPress with @ptahdunbar

Automated Testingincreases your productivity

#dc4d - Automated Testing in WordPress with @ptahdunbar

Automated Testingfacilitates more shipping

#dc4d - Automated Testing in WordPress with @ptahdunbar

Automated Testingscales with you

#dc4d - Automated Testing in WordPress with @ptahdunbar

Automated Testingis your professional duty

as a developer

#dc4d - Automated Testing in WordPress with @ptahdunbar

Thank youAutomated Testing in WordPress

Pirate Dunbar@ptahdunbaryarr@piratedunbar.com

Rate this talk:https://joind.in/10115

Recommended