Sviluppo guidato dai tests in ambiente WordPress. La prima parte della frase fa aggrottare la fronte in condizioni normali: in ambiente WordPress assume un che di mistico ed irraggiungibile. Non è così.
PARTIAMO DA UN ESEMPIO
Ho creato un plugin
Il plugin svolge le sue funzioni sulla pagina /wpday
Se lo slug /wpdaye' gia' occupato da una vera pagina
mostriamo una notice per l'utente proponendo soluzioni
ACCEPTANCE TEST
Questo e' un test di accettazione ("acceptance") scritto in
:Codeception
$I = new AcceptanceTester($scenario);
$I->wantTo('vedere una notifica senza potere modificare lo slug');
$I->loginAs('utente','password');
$I->activatePlugin('wpday/wpday.php')
$I->see("Lo slug /wpday e' associato alla pagina "WPDay"!");
FUNCTIONAL/INTEGRATION TEST
Questo e' un test funzionale o di integrazione ("acceptance")
scritto in ed usandoCodeception PhpUnit
public function test_shows_non_actionable_notice_to_not_editor()
{
$user = $this->getMock('WP_User');
$user->expects($this->any())->method('has_cap')->willReturn(false);
global $current_user;
$current_user = $user;
$notice_generator = new Notice_Factory();
$notice = $notice_generator->make_notice();
$this->assertInstanceOf('NonActionableNotice', $notice);
}
FUNCTIONAL/INTEGRATION TEST 2
Testiamo ora che un utente che puo' modificare la pagina
veda una notifica con un call to action:
public function test_shows_actionable_notice_to_editor()
{
$user = $this->getMock('WP_User');
$user->expects($this->any())->method('has_cap')->willReturn(true);
global $current_user;
$current_user = $user;
$notice_generator = new Notice_Factory();
$notice = $notice_generator->make_notice();
$this->assertInstanceOf('ActionableNotice', $notice);
}
UNIT TEST
Questo e' uno unit test scritto usando :PhpUnit
public function test_notice_shows_link_to_edit_page()
{
$url = 'http://local.dev/wp/wp-admin/post.php?post=2&action=edit';
$title = 'Pagina WPDay';
$sut = new ActionableNotice();
$notice_message = $sut->get_notice_for($url, $title);
$expected = "<a href='{$url}'>modifica lo slug di {$title}</a>";
$this->assertContains( $expected, $notice_message);
}
PERCHE'? LE MIE RAGIONI
Possiamo parlare per ore di ragioni a favore e contro, queste
sono le mie.
Buone pratiche di programmazione
Esplorazione caratteristiche
Memoria contestuale
Gamification
BUONE PRATICHE DI PROGRAMMAZIONE
Un tweet di (quello di Laracasts)
Nessuno vuole ammettere che la maggiore parte delle buone
prassi di PHP spesso si riducono a "Bene, devi strutturarlo
cosi' per poterlo testare o sostituire."
@jeffrey_way
ESPLORAZIONE CARATTERISTICHE
Il processo di "feature scoping" trasforma idee che sono
nella testa del cliente in codice: ma dove avviene questa
trasformazione?
Si possono scrivere consegne vaghe ma non si puo'
scrivere codice vago.
I test costringono uno sviluppatore a porre domande al QA
team, il QA team allo stratega, lo stratega al cliente.
CARATTERISTICHE E BUGS
Nuova feature? Nuovi test!
Bug? Un test che riproduce il bug!
Quali i passi per riprodurre un bug? Esattemente.
MEMORIA CONTESTUALE
Lui sa tutto... ma ha smesso di fare il
programmatore per fare la ballerina.
Le persone dimenticano. Tutto. Subito.
I test sono memoria esterna.
Fra un anno i test che ho scritto oggi funzioneranno ancora;
la mia memoria...
PER ROMPERLO DEVI CONOSCERLO
Per essere piu' efficaci nell'uccidere gli umani
un Terminator ha una mappa dettagliata
della anatomia umana. - Terminator 2
La necessita' di scrivere tests di accettazione, integrazione o
unita' costringe a chiedersi:
che cosa fa?
che cosa non fa?
come funziona?
TL;DR
"Too long; did not read."
i test sono documentazione
i test costringono chi scrive codice a chiedersi se cio' che fa
e' chiaro, se ha senso
un test che fallisce segnala in maniera chiara cosa non va e
dove
COME SI FA?
Diversi approcci e framework
Io vi parlo di un approccio TDD composto da accettazione,
integrazione, unita'
Io vi parlo di test principalmente in PHP
APPROCCI
BDD - Behaviour-Driven Development ("Sviluppo guidato
dal comportamento")
TDD - Test-Driven Development ("Sviluppo guidato dai
test")
DDD - Design-Driven Development ("Sviluppo guidato dal
design")
Vanno bene tutti! Basta che ne usiate uno.
FRAMEWORKS
Sono tantissimi ed ognuno copre parti particolari, i principali:
Cucumber
Behat
Rspec
Codeception
PHPUnit
PHPSpec
altri
Io vi parlo di Codeception
ATTORI
E' importante capire chi e' l'attore simulato in ogni tipo di test
Accettazione - un utente che utilizza la applicazione
mediante la sua interfaccia
Integrazione - la applicazione che utilizza gli oggetti che la
compongono per gesire una richiesta
Unita' - un singolo ggetto/funzione che viene utilizzato da
altri oggetti
IL COSTO DELLA SIMULAZIONE
Simulare la manipolazione di una stringa
Simulare il processo di aggiornamento del valore meta di
un post
Simulare il processo di login, modifica di un post, update e
reload mediante interfaccia
Queste simulazione hanno una crescente complessita'.
LA FRAGILITA' DELLA SIMULAZIONE
Piu' una simulazione e' elaborata piu':
simula comportamenti e stati ognuno indipendentemente
variabile
e' laboriosa da mantenere
si presta all'abbandono
TEST SET UP - COMPOSER
https://getcomposer.org/
e' un tool scritto in PHP per gestire le
dipendenze di un progetto
il "progetto" e' un plugin oppure un tema (ma anche un sito)
Composer
Una volta installato Composer
composer init
Seguono domande sul progetto...
TEST SET UP - COMPOSER 2
Una volta che e' inizializzato gli chiediamo di
installare come dipendenza del progetto
Composer
wp-browser
composer require --dev lucatume/wp-browser
viene installato wp-browsercome dipendenza di sviluppo
Segue (lunga) installazione...
TEST SET UP - WPCEPT BOOTSTRAP
Inizializziamo ("bootstrap") la struttura dei tests
wpcept bootstrap
viene creato un file di configurazione di ,
composer.json
viene creata la cartella tests
Codeception
TEST SET UP - CONFIGURAZIONE DEI MODULI
I moduli che fanno parte della libreria vengono inizializzati
con dei valori di defaults
vanno configurati per la installazione locale
WPLoader:
wpRootFolder: /Users/Luca/Sites/wp
dbName: wordpress-tests
dbHost: localhost
dbUser: root
dbPassword: password
tablePrefix: wptests_
domain: wp.dev
adminEmail: admin@wp.dev
title: 'WordPress Tests'
plugins:
- plugin-a/plugin-a.php
- plugin-b/plugin-b.php
activatePlugins:
- plugin-a/plugin-a.php
- plugin-b/plugin-b.php
TEST SET UP - CONFIGURAZIONE DEI MODULI 2
I moduli che interagiscono con il database vanno "puntati"
su di esso
I moduli che "guidano" un browser vanno configurati
WPWebDriver:
url: 'http://wp-acceptance.dev'
browser: phantomjs
port: 4444
restart: true
wait: 2
adminUsername: admin
adminPassword: password
adminUrl: /wp-admin
Va fatto una volta sola!
TEST SET UP - GENERARE ACCEPTANCE TESTS
Generare un test di tipo Cest per la suite acceptance
wpcept generate:cest acceptance MyFirstAcceptance
Output
Test was created in plugin-a/tests/acceptance/MyFirstAcceptanceCest.php
TEST SET UP - GENERARE FUNCTIONAL TESTS
Generare un test di tipo Test per la suite acceptance
wpcept generate:wpunit functional PostSaver
Output
Test was created in plugin-a/tests/functional/PostSaveTest.php
TEST SET UP - GENERARE UNIT TESTS
Generare un test di tipo PHPUnit per la suite acceptance
wpcept generate:phpunit unit ActionableNotice
Output
Test was created in plugin-a/tests/unit/ActionableNoticeTest.php
TEST SET UP - WP UNIT
Il comando wpcept generate:wpunit ...genera uno
"unit" test alla maniera della Core suite
<?php
class PostSaverTest extends CodeceptionTestCaseWPTestCase {
protected $backupGlobals = false;
public function setUp() {
// before
parent::setUp();
// your set up methods here
}
public function tearDown() {
// your tear down methods here
// then
parent::tearDown();
}
TEST SET UP - RUN
Finalmente facciamo partire i test
./bin/vendor/codecept run
DA FARE
installate WP Browser in una cartella vuota
configurate la suite
generate un WPTestCase
codecept runper controllare che tutto vada
scrivete un test scemo
wpcept generate:wpunit functional SomeClass
public function testICanUseWPFunctions(){
$this->assertEquals('foo/', trailingslashit('foo'));
}
Complimenti avete scritto un primo test per WordPress!
LINKS E LIBRI
Composer -
PhpUnit -
Codeception -
WP Browser -
Libro -
https://getcomposer.org/
https://phpunit.de/
http://codeception.com/
https://github.com/lucatume/wp-browser
Growing Object-Oriented software, guided by tests