41
Effizientere WordPress-Plugin-Entwicklung mit Softwaretests Martin Schütte

Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

  • Upload
    deck36

  • View
    654

  • Download
    1

Embed Size (px)

DESCRIPTION

Introduction: How to use Unit Testing (TDD) and Behaviour Testing (BDD) for Wordpress, building a Continuous Integration workflow.

Citation preview

Page 1: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

EffizientereWordPress-Plugin-Entwicklung mit

Softwaretests

Martin Schütte

Page 2: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

About DECK36

• Small team of 7 engineers• Longstanding expertise in designing, implementing and operatingcomplex web systems

• Developing own data intelligence-focused tools and web services• Offering our expert knowledge in Automation & Operation,Architecture & Engineering, Analytics & Data Logistics

Page 3: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

1. Dev & Test Environments

2. Testing VariantsStatic Code AnalysisUnit TestingIntegration TestingBehaviour Testing

3. Integration & Automation

Page 4: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Main Questions

How can I know (my) software is correct?

How does my boss know software is correct?

How do I know software implements a given design?

How can we discuss what “correct” is, anyway?

We always need:• implicit assumptions,• explicit specifications.

Page 5: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Levels of Testing

..

abstract

.

specific

.

Unit Tests

.

Integration Tests

.

AcceptanceTests

Page 7: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Use a DevEnvironment

Page 8: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Vagrant

Configuration tool for (VirtualBox) VMsetup and provisioning.

“Local cloud”• Self service• Instant provisioning

Useful for development• reproducible environment• independent PHP 5.x setups• try things and not jeopardiseyour dev environment

Page 9: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

VagrantPress

$ git clone https://github.com/chad-thompson/vagrantpress.git$ cd vagrantpress$ vagrant up

will setup VM with:

• Ubuntu Precise (12.04), Apache 2.2, MySQL 5.5, PHP 5.3• Wordpress 3.8• phpMyAdmin• PHPUnit• phpcs, phploc, phpdepend, …

Page 10: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Testing Variants

Page 11: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Coding Style

$ phpcs --standard=WordPress freifunkmeta.php

FILE: [...]/plugins/freifunkmeta/freifunkmeta.php---------------------------------------------------------------------FOUND 360 ERROR(S) AND 406 WARNING(S) AFFECTING 338 LINE(S)---------------------------------------------------------------------

21 | ERROR | Incorrect indentation; expected 1 space, found 422 | WARNING | Line is indented with space not tab33 | ERROR | String "Unable to retrieve URL %s, error: %s" does

| | not require double quotes; use single quotes instead322 | ERROR | Closing parenthesis of a multi-line function

| | definition must be on a line by itself440 | ERROR | Expected next thing to be a escaping function,

| | not '"<option value='$city' $selected>$prettycity| | </option>"'

Page 12: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Code Metrics

$ php pdepend_summary.php freifunkmeta.php

Package/Class Method LoC %Comment CCN NPath------------- ------ --- -------- --- -----FF_Meta output_ff_contact 49 6.1 10 384FF_Meta shortcode_handler 41 2.4 9 48FF_Community __construct 12 0.0 7 15625FF_Meta register_stuff 18 0.0 5 16FF_Meta aux_get_all_locations 23 8.7 5 6FF_Community make_from_city 15 0.0 4 20[...]

Page 13: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Example Plugin: Freifunkmeta

..WP Blog.

FF_Meta

.

WP Core

.

Other Plugins

.

FF_Community

.

FF_Dir

.

OutputFormatter

.

HTTP GetService

Page 14: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Unit Testing

..WP Blog.

FF_Meta

.

WP Core

.

Other Plugins

.

FF_Community

.

FF_Dir

.

OutputFormatter

.

HTTP GetService

Page 15: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Simple PHPUnit Test Case

class LowLevelTests extends PHPUnit_Framework_TestCase {function setUp() {

$this->FFM = new FF_Meta();}

function test_output_ff_state() {$data = array("state" => array("nodes" => 429));$ret = $this->FFM->output_ff_state($data);$this->assertRegExp('/429/', $ret);

}}

Page 16: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Unit Testing (contd.)

..WP Blog.

FF_Meta

.

WP Core

.

Other Plugins

.

FF_Community

.

FF_Dir

.

OutputFormatter

.

HTTP GetService

Page 17: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Integration Testing

..WP Blog.

FF_Meta

.

WP Core

.

Other Plugins

.

FF_Community

.

FF_Dir

.

OutputFormatter

.

HTTP GetService

Page 18: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Unit Testing with Mock Object

..WP Blog.

FF_Meta

.

WP Core

.

Other Plugins

.

FF_Community

.

FF_Dir

.

OutputFormatter

.

HTTP GetService

Page 19: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Example: Test with Dependency Injection

class MockDataService {function get($url) {

return $some_fixed_data;}

}

class WpIntegrationTests extends WP_UnitTestCase {function setUp() {

parent::setUp();// get plugin instance and replace ext. data service:$this->plugin = $GLOBALS['wp-plugin-ffmeta'];$this->plugin->reset_external_data_service(

new MockDataService() );}

// ...

Page 20: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Example: Test with Dependency Injection

// ...function test_post_ff_services() {

$post_attribs = array('post_title' => 'Test','post_content' => '[ff_services]' );

$post = $this->factory->post->create_and_get($post_attribs );

// w/o filter:$this->assertEquals($post_content, $post->post_content);

// with filter:$output = apply_filters( 'the_content',

$post->post_content );$this->assertRegExp('/radio\.ffhh/', $output);

}}

Page 21: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

PHPUnit Output

Page 22: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Behaviour Testing

..WP Blog.

FF_Meta

.

WP Core

.

Other Plugins

.

FF_Community

.

FF_Dir

.

OutputFormatter

.

HTTP GetService

Page 23: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

WordPress Shortcode Plugin Test..

Feature: Use ShortcodesIn order to use my PluginAs a website authorI need to write posts with shortcodes

Background:Given I am logged in as "admin" with "vagrant"

Scenario: Without the pluginGiven the plugin "freifunkmeta" is "inactive"When I write a post with title "test" and content "[ff_contact]"Then I should see "ff_contact"

Scenario: With the pluginGiven the plugin "freifunkmeta" is "active"When I write a post with title "test" and content "[ff_contact]"Then I should see "Twitter" in the ".ff_contact" elementAnd I should not see "ff_contact"

Page 24: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Behat Output

Page 25: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Implementation / Translation

A look behind the curtain:• framework is clever but not magical• some translation needed• statements have to become executable code

Mechanism:• plain sentence → method name• quoted words → arguments• matching with annotated regular expressions• methods yield success, exception, or pending exception

Page 26: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Example: Behat Context (PHP)

/*** from MinkContext* Checks, that page contains specified text.** @Then /^(?:|I )should see "(?P<text>(?:[^"]|\\")*)"$/*/

public function assertPageContainsText($text){

$this->assertSession()->pageTextContains($this->fixStepArgument($text));

}

Page 27: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

The Big Picture

..Features.

Step Definitions

.

WebDriver

.

Browser

Page 28: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

The Big Picture

..Features.

Behat (PHP)

.

cucumber.js

.

Cucumber(Ruby)

.

PhantomJS

.

Goutte

.

Selenium

.

Firefox

.

Chrome

Page 29: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Unit & Behaviour Testing

Unit Tests• unit testing• programmers• programming language• bottom-up• assertXYZ• tests derived from user stories

⇒ development tool

Behaviour Tests• acceptance test scenarios• non-developers• language of business domain• top-down / outside-in• X should do Y• execute user stories

⇒ design & communication tool

Page 30: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Automate!

Page 31: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Scripting

Basis for all automation.Lots of useful builtins and packages:

• wp core download/install/config/…• wp export/import• wp plugin get/install/update/…• wp scaffold _s/plugin/plugin-tests• wp server

Page 32: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

wp scaffold

Generate skeleton code for a new plugin & unit tests:

$ cd wordpress/wp-content/plugins$ wp scaffold plugin-tests awesome$ find awesomeawesome/awesome/awesome.phpawesome/binawesome/bin/install-wp-tests.shawesome/testsawesome/tests/bootstrap.phpawesome/tests/test-sample.phpawesome/.travis.ymlawesome/phpunit.xml

Page 33: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

wp scaffold (contd.)

Create WP instance and run unit tests:$ cd awesome$ bash ./bin/install-wp-tests.sh wp_tests root vagrant latest...$ phpunitPHPUnit 4.0.17 by Sebastian Bergmann.[...]

Configuration read from [...]/plugins/awesome/phpunit.xml

.

Time: 5.52 seconds, Memory: 23.50Mb

OK (1 test, 1 assertion)

Page 34: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Version Control

• use version control!• many possible workflows,e. g. branches for dev and release

• use pre-commit hooks,e. g. with php -l syntax check

Page 35: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Travis-CI

Continuous Integration service for GitHub1. gets notified on push

2. builds project

3. runs phpunit

4. summarizes results,alert on failure

Page 36: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Example .travis.yml

language: php

php:- 5.4- 5.5- hhvm

env:- WP_VERSION=3.8.3- WP_VERSION=latest

before_script:- bash bin/install-wp-tests.sh wordpress_test \

root '' localhost $WP_VERSION

script: phpunit

Page 38: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Automated Testing

Target: no manual effort.

Continuous Integration:• frequent code check-ins• verified by automatedbuilds and tests

• quickly find bugsand regressions

Continuous Deployment:• (semi-)automated deployment• plan for rollback

Page 39: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Costs and Benefits of Testing

• Testing (like Documentation) has a cost• usually: productivity improvement > cost• but find the right balance

Page 40: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Conclusion

I get paid for code that works, not for tests, so my philosophy is to testas little as possible to reach a given level of confidence.

– Kent Beck

Links

• http://phpqatools.org/: PHP Quality Assurance Toolchain• http://wpgear.org/: compendium of useful WP developer tools• http://wptest.io/: test data for WP plugins and themes

• Ptah Dunbar: Automated Testing in WordPress, Really?!• tuts+ articles by Tom McFarlin• Conversation “Is TDD Dead?”

Page 41: Effizientere WordPress-Plugin-Entwicklung mit Softwaretests

Thank You