mantenere una distribuzione drupal attraverso test coverage: paddle case study

Post on 14-Apr-2017

285 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

MANTENERE UNA DISTRIBUZIONE DRUPALATTRAVERSO TEST COVERAGE

PADDLE CASE STUDY

https://github.com/brummbar/drupal-day-2015

ABOUT ME

FRANCESCO SARDARA

Backend e frontend

Email:francesco.sardara@kanooh.beD.o: Sardara

PER CHI LAVORO

COSA È PADDLE

FLEMISH GOVERNMENTFramework contract

Unico referente per sito web, hosting e supporto;frontend che segue le specifiche di branding del governoFiammingo;focus sulla gestione dei contenuti (revisioni, workflow);usabilità del backend per utenti non esperti;commenti, multilingua, contatti, quiz, rss, newsletter,protected pages.

WORKFLOW DI LAVORO

Sprint di 2 settimane↓

Soft release↓

Hard releaseRilascio in produzione

ORGANIZZAZIONE DELLO SPRINTOpen/ReopenedDevelopmentTestingQAUAT

ANATOMIA DI UN TICKETUser story / descrizione bugUAT stepsDefinition of done

DEFINITION OF DONEFunctionally completeAutomated tests cover UAT instructionsAutomated Simpletest tests passing within the last 24hAutomated Selenium tests passing within the last 24hWorking upgrade path from the last release in place...

AUTOMATED TESTSSimpletest e SeleniumShoov.io / WebdrivercssEseguiti su server tramite Jenkins CI

Esecuzioni giornaliere automaticheEsecuzioni manuali per ticket

Esecuzione remota su Browserstack

SELENIUMautomatizzazione di test su applicazioni webampiamente supportato in svariati linguaggiSelenium IDE e Webdriver

COSA TESTIAMO IN SELENIUMfunzionalità personalizzateintegrazioni tra modulifunzionalità Javascriptregressioni

QUALCHE NUMERO746 test10966 asserzionitempo di esecuzione di 18 orerichiedono 2/3 del tempo di sviluppo

PAGE OBJECT PATTERN

PUNTI CHIAVEriduzione della duplicazione del codicefacilità nell’aggiornare la relativa classe se gli elementidella pagina cambianopossibilità di sfruttare appieno i meccanismi di ereditarietà

REGOLEsolo la classe deve contenere XPath / selettori CSSrelativi all’elementonessuna assertion deve essere fatta all’interno dellaclasse

PAGE OBJECT PATTERN INPADDLE

STRUTTURA CARTELLE

ANATOMIA DI UNA CLASSE PAGE OBJECT

Il metodo costruttore contiene sempre una referenza aWebdriver 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; }

Tutte le proprietà che rappresentano altri Page Object sonogestite 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-und-0-value' break; } throw new FormFieldNotDefinedException($name); }

PERCHÉ USARE __GET() ?Legacy codeSeparazione 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();

RISULTATO DEL TEST

SOPRAVVIVERE AI TESTApprocci e best practices

RANDOM FAILING TESTSPer RFT si indicano quei test che senza nessun

cambiamento nel codice o nei dati di test(*), il loro risultatonon è costante.Cause comuni:

differenze hardwaredati di test

IMPLICIT E EXPLICIT WAITSIl tempo di attesa implicito rappresenta per quanto tempoWebdriver deve interrogare il DOM in attesa di trovare un

elemento se esso non è disponibile immediatamente.Il tempo di attesa esplicito rappresenta per quanto tempoWebdriver deve aspettare una certa condizione prima di

proseguire con l'esecuzione.

IMPLICIT WAIT// Add a new definition. $this->configurePage->contextualToolbar->buttonAdd->click(); $modal = new GlossaryDefinitionModal($this); $modal->form->definition->fill('The awesome definition');

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); }

RANDOMIZZARE I DATI DI TESTPro

Evitare parzialmente "collisioni"tra contenutiTrovare casi limiteSimulare un vero utilizzo delsistema

Contro

La randomizzazione rende iltest non completamenteprevedibile

L'APPROCCIO DI PADDLELa generazione dei contenuti è randomizzata.I contenuti vengono lasciati intatti a meno che la loropresenza non complichi la realizzazione del test.

SOPRAVVIVERE AI TEST(REPRISE)

Approcci in Paddle

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(), ) ); }

AJAX CALLBACKS// ... $form['list_id'] = array( '#type' => 'select', '#title' => t('List'), '#required' => TRUE, '#ajax' => array( 'callback' => 'mailchimp_campaign_list_segment_callback', ), ); // ...

/** * Marks the element as if it is waiting for AJAX callbacks. * * @see \Kanooh\Paddle\Pages\Element\Form\AutoCompletedText::markAsWaitingForAutoCompleteResults() */ public function markAsWaitingForAjaxCallback(\PHPUnit_Extensions_Selenium2TestCase_Element { $this->webdriver->execute( array( 'script' => "arguments[0].className += ' progress-disabled';", 'args' => array($element->toWebDriverObject()), ) ); }

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'); // ...

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'); }

IMPROVING SELENIUMRESULTS

RIPETIZIONI MULTIPLE PER EVITARE L'INTRODUZIONE DI RFT$ base_url=http://paddle.dev ./vendor/bin/phpunit --repeat=3 \ tests/Kanooh/Paddle/App/ContactPerson/EnableDisableTest.php

RICONOSCERE LE RFT$ ./vendor/bin/phpunit --repeat=2 --only-repeat-failed tests/

VELOCIZZARE L'ESECUZIONEesecuzione in parallelo dei testsfruttare drupal/drupal-driver per rimuovere interazionibrowser non necessarie

VISUAL REGRESSIONWEBDRIVERCSS E SHOOV.IO

WEBDRIVERCSSTool di automatizzazione per test di visual regression per

WebdriverIO.

SHOOV.IOTool di visual regression e live monitoring.

Wrapper per WebdrivercssHeadless Drupal per lo storage degli screenshotAngular.js web-app per il confronto visualeIntegrazione con Github (login, commits, pull request)Gratuito (?)

Q&A

Per domande o suggerimenti, scrivetemifrancesco.sardara@kanooh.be

GRAZIE PERL'ATTENZIONE.

top related