8. FLEMISH GOVERNMENT
Framework contract
Unico referente per sito web, hosting e supporto;
frontend che segue le specifiche di branding del governo
Fiammingo;
focus sulla gestione dei contenuti (revisioni, workflow);
usabilità del backend per utenti non esperti;
commenti, multilingua, contatti, quiz, rss, newsletter,
protected pages.
12. ANATOMIA DI UN TICKET
User story / descrizione bug
UAT steps
Definition of done
13. DEFINITION OF DONE
Functionally complete
Automated tests cover UAT instructions
Automated Simpletest tests passing within the last 24h
Automated Selenium tests passing within the last 24h
Working upgrade path from the last release in place
...
14. AUTOMATED TESTS
Simpletest e Selenium
Shoov.io / Webdrivercss
Eseguiti su server tramite Jenkins CI
Esecuzioni giornaliere automatiche
Esecuzioni manuali per ticket
Esecuzione remota su Browserstack
20. PUNTI CHIAVE
riduzione della duplicazione del codice
facilità nell’aggiornare la relativa classe se gli elementi
della pagina cambiano
possibilità di sfruttare appieno i meccanismi di ereditarietà
21. REGOLE
solo la classe deve contenere XPath / selettori CSS
relativi all’elemento
nessuna assertion deve essere fatta all’interno della
classe
26. Il metodo costruttore contiene sempre una referenza a
Webdriver e all'oggetto Selenium.
/**
* Construct a new GlossaryDefinitionTableRow.
*
* @param WebDriverTestCase $webdriver
* The Selenium web driver test case.
* @param PHPUnit_Extensions_Selenium2TestCase_Element $element
* The webdriver element of the definition table row.
*/
public function __construct(WebDriverTestCase $webdriver, $element)
{
parent::__construct($webdriver);
$this->element = $element;
}
27. Tutte le proprietà che rappresentano altri Page Object sono
gestite tramite magic get.
/**
* {@inheritdoc}
*/
public function __get($name)
{
switch ($name) {
case 'saveButton':
return $this->element->byXPath('.//input[contains(@id, "edit-save")]'
break;
case 'definition':
return new Text($this->webdriver, $this->element->byName('definition'
break;
case 'description':
return new Wysiwyg($this->webdriver, 'edit-field-glossary-description
break;
}
throw new FormFieldNotDefinedException($name);
}
28. PERCHÉ USARE __GET() ?
Legacy code
Separazione dalle proprietà
Linearità di lettura
$this->configurePage->go();
$this->configurePage->contextualToolbar->buttonAdd->click();
$modal->form->definition->fill($title);
$modal->form->description->setBodyText($description);
$modal->form->saveButton->click();
$modal->waitUntilClosed();
29. ESEMPIO DI TEST CASE
GlossaryTest.php
testGlossaryDefinitionHighlighting
33. RANDOM FAILING TESTS
Per RFT si indicano quei test che senza nessun
cambiamento nel codice o nei dati di test(*), il loro risultato
non è costante.
Cause comuni:
differenze hardware
dati di test
34. IMPLICIT E EXPLICIT WAITS
Il tempo di attesa implicito rappresenta per quanto tempo
Webdriver deve interrogare il DOM in attesa di trovare un
elemento se esso non è disponibile immediatamente.
Il tempo di attesa esplicito rappresenta per quanto tempo
Webdriver deve aspettare una certa condizione prima di
proseguire con l'esecuzione.
35. IMPLICIT WAIT
// Add a new definition.
$this->configurePage->contextualToolbar->buttonAdd->click();
$modal = new GlossaryDefinitionModal($this);
$modal->form->definition->fill('The awesome definition');
36. EXPLICIT WAIT
// Add a new definition.
$this->configurePage->contextualToolbar->buttonAdd->click();
$modal = new GlossaryDefinitionModal($this);
$modal->waitUntilOpened();
$modal->form->definition->fill('The awesome definition');
public function waitUntilOpened()
{
$callable = new SerializableClosure(...);
$this->webdriver->waitUntil($callable, $this->timeout);
}
37. RANDOMIZZARE I DATI DI TEST
Pro
Evitare parzialmente "collisioni"
tra contenuti
Trovare casi limite
Simulare un vero utilizzo del
sistema
Contro
La randomizzazione rende il
test non completamente
prevedibile
38. L'APPROCCIO DI PADDLE
La generazione dei contenuti è randomizzata.
I contenuti vengono lasciati intatti a meno che la loro
presenza non complichi la realizzazione del test.
40. CKEDITOR
/**
* Sets the body text.
*
* @param string $text
* The text to enter in the body.
*/
public function setBodyText($text)
{
$this->webdriver->byId('cke_' . $this->editorId);
$this->webdriver->execute(
array(
'script' => "CKEDITOR.instances['{$this->editorId}'].setData('"
'args' => array(),
)
);
}
42. /**
* Marks the element as if it is waiting for AJAX callbacks.
*
* @see KanoohPaddlePagesElementFormAutoCompletedText::markAsWaitingForAuto
*/
public function markAsWaitingForAjaxCallback(PHPUnit_Extensions_Selenium2TestCas
{
$this->webdriver->execute(
array(
'script' => "arguments[0].className += ' progress-disabled';",
'args' => array($element->toWebDriverObject()),
)
);
}
43. MASTERING THE STALE
// ...
$form = $image_pane_type->getForm();
$form->showCaption->check();
// Submit the form and reload the modal.
$form->submit();
// Test something else.
$form->captionTextArea->fill('Oooops');
// ...
44. EXPLOITING THE STALE
// Waits until the current page is loaded.
public function waitUntilPageIsLoaded()
{
$body = $this->bodyElement;
$webdriver = $this->webdriver;
$callable = new SerializableClosure(
function () use ($body, $webdriver) {
try {
$body->click();
} catch (PHPUnit_Extensions_Selenium2TestCase_WebDriverException
return true;
}
}
);
$this->webdriver->waitUntil($callable, $this->webdriver->getTimeout());
$this->webdriver->waitUntilElementIsDisplayed('//body');
}
51. SHOOV.IO
Tool di visual regression e live monitoring.
Wrapper per Webdrivercss
Headless Drupal per lo storage degli screenshot
Angular.js web-app per il confronto visuale
Integrazione con Github (login, commits, pull request)
Gratuito (?)
52. L'APPROCCIO DI PADDLE AL VR
Configuration
Single test
https://github.com/brummbar/visual-regression