nashville symfony functional testing

18
FUNCTIONAL TESTING (overview) Functional tests validate parts of your applications. Functional tests simulate a browsing session to assert desired user outcomes. They automate requests and check elements in the response. It is advantageous to write your functional tests to correspond to individual user stories. User Story: As an Administrator I want to create a company so I can manage companies Wednesday, January 6, 2010

Upload: brent-shaffer

Post on 15-Jan-2015

2.793 views

Category:

Technology


1 download

DESCRIPTION

Symfony functional testing is vital to your project's success. Learn how to easily extend the framework to fit your application's custom needs.

TRANSCRIPT

Page 1: Nashville Symfony Functional Testing

FUNCTIONAL TESTING(overview)

Functional tests validate parts of your applications.

Functional tests simulate a browsing session to assert desired user outcomes. They automate requests and check elements in the response. It is advantageous to write your functional tests to correspond to individual user stories.

User Story:As an Administrator I want to create a company so I can manage companies

Wednesday, January 6, 2010

Page 2: Nashville Symfony Functional Testing

WHY WRITE THEM?

-BETTER TEST COVERAGE!!

- Cover areas unit tests can’t reach

- Unit Tests: Model Layer

- Functional Tests: View and Control Layers

- Mimic Functional QA

- Write tests according to client-approved user

stories.

Wednesday, January 6, 2010

Page 3: Nashville Symfony Functional Testing

TOOLS FOR FUNCTIONAL TESTING

Cucumber

“Cucumber is designed to allow you to execute feature documentation

written in plain text (often known as ‘stories’).”

Selenium“Selenium is written in JavaScript; it's designed to run in a real browser to

test compatibility with a real browser”

•Uses a real browser

•Writes test in JavaScript, can play back through any browser

•We will discuss this later

Wednesday, January 6, 2010

Page 4: Nashville Symfony Functional Testing

-Bootstrap Symfony Core

-sfBrowser

-Symfony class simulating a true browser

-Testing Blocks

-sfTestFunctional split into multiple classes- sfTesterResponse, sfTesterRequest, sfTesterDoctrine, sfTesterUser, sfTesterForm

-Extend the functional test framework for

custom functionality

FUNCTIONAL TESTING IN SYMFONY

Wednesday, January 6, 2010

Page 5: Nashville Symfony Functional Testing

EXTEND THE TEST FRAMEWORKSubclass sfTestFunctional

class csTestFunctional extends sfTestFunctional{ public function clickAndCheck($link, $module, $action, $statusCode = 200) { return $this->click($link)->isModuleAction($module, $action, $statusCode); }

public function isModuleAction($module, $action, $statusCode = 200) { $this->with('request')->begin()-> isParameter('module', $module)-> isParameter('action', $action)-> end()->

with('response')->begin()-> isStatusCode($statusCode)-> end();

return $this; }}

Wednesday, January 6, 2010

Page 6: Nashville Symfony Functional Testing

USE FIXTURES// test/data/urls.yml- url: /blog module: blog action: index statusCode: 200- url: /blog/new module: blog action: new statusCode: 200- url: /blog/edit module: blog action: edit statusCode: 401

// test/functional/frontend/routeTest.php foreach(sfYaml::load(sfConfig::get('sf_test_dir').'/data/forms.yml') as $route) { $browser ->get($route['url']) ->isModuleAction($route['module'], $route['action'], $route['statusCode']) ; }

Simplify Repetitive Tests!

Create a YAML file to hold data

AND...

Wednesday, January 6, 2010

Page 7: Nashville Symfony Functional Testing

CREATE YOUR OWN TESTERExtend sfTesterForm

class csTesterForm extends sfTesterForm{ // Called at every occurence of $browser->with('form') public function initialize() { // Load form into local variable parent::initialize(); } // Called when a page is requested // (at every occurence of $browser->call()) public function prepare() { } public function fill($name, $values = array()) { $formValues = Doctrine_Lib::arrayDeepMerge($this->getFormValues($name), $values);

foreach ($formValues as $key => $value) { $this->setDefaultField($key, $value); }

return $this->getObjectToReturn(); }}

Wednesday, January 6, 2010

Page 8: Nashville Symfony Functional Testing

// test/data/forms.ymllogin_bad: signin: username: admin password: wrongpassword

login: signin: username: admin password: rightpassword login2: signin[username]: admin signin[password]: rightpassword

// lib/test/csTesterForm.class.phppublic function __construct(sfTestFunctionalBase $browser, $tester){ parent::__construct($browser, $tester); if (file_exists(sfConfig::get('sf_test_dir').'/data/forms.yml')) { $this->setFormData(sfYaml::load(sfConfig::get('sf_test_dir').'/data/forms.yml')); }}

Extend sfTesterForm (continued)

Create Form Fixtures

Load them into your Tester!

// test/functional/backend/loginTest.php$browser = new csTestFunctional(new sfBrowser(), null, array('form' => 'csTesterForm'));

Instantiate Your Classes

Wednesday, January 6, 2010

Page 9: Nashville Symfony Functional Testing

USE FACTORIESHelpful classes to generate objects and data

class sfFactory{ protected static $lastRandom = null; public static function generate($prefix = '') { self::$lastRandom = $prefix.rand(); return self::$lastRandom; } public static function last() { if (!self::$lastRandom) { throw new sfException("No previously generated random available"); } return self::$lastRandom; }}

Wednesday, January 6, 2010

Page 10: Nashville Symfony Functional Testing

PUTTING IT ALL TOGETHER

$browser = new csTestFunctional(new sfBrowser(), null, array('form' => 'csTesterForm', 'doctrine' => 'sfTesterDoctrine'));

$browser->info('Create a new Company');

$browser ->login() ->get('/company/new') ->with('form')->begin() ->fill('company', array('company[name]' => sfFactory::generate('Company'))) ->end()

->info('Create Company "'.sfFactory::last().'"') ->click('Save and add') ->with('form')->begin() ->hasErrors(false) ->end() ->followRedirect()

->with('doctrine')->begin() ->check('Company', array('name' => sfFactory::last())) ->end();

Verify record exists

Fill the form with a unique value

Initialize your testers

Wednesday, January 6, 2010

Page 11: Nashville Symfony Functional Testing

Success!

Wednesday, January 6, 2010

Page 12: Nashville Symfony Functional Testing

CAN YOU THINK OF OTHER USEFUL TESTERS?

Wednesday, January 6, 2010

Page 13: Nashville Symfony Functional Testing

USE PLUGINSswFunctionalTestGenerationPlugin

Add to your dev toolbar

Quickly stub symfony functional tests while clicking through the browser

Wednesday, January 6, 2010

Page 14: Nashville Symfony Functional Testing

sfTaskExtraPlugin$ ./symfony generate:plugin sfScraperPlugin

--module=sfScraper --test-application=frontend

SO YOU WANNA TEST YOUR PLUGINS?

Plugin Skeleton Test Fixtures

Wednesday, January 6, 2010

Page 15: Nashville Symfony Functional Testing

sfTaskExtraPlugin (continued)

$ ./symfony test:plugin sfScraperPlugin

$ ./symfony test:functional frontend sfScraperActions

$ ./symfony test:unit sfScraper

// config/ProjectConfiguration.class.phppublic function setupPlugins(){ $this->pluginConfigurations['sfScraperPlugin']->connectTests();}

Run all plugin tests

Run tests individually

Run plugin tests alongside project tests$ ./symfony test:all

Connect plugin tests in ProjectConfiguration and....

Wednesday, January 6, 2010

Page 16: Nashville Symfony Functional Testing

A LITTLE TASTE OF CUCUMBER

Uses “Scenarios”

that are then interpreted using

“Steps”

Scenario: See all vendors Given I am logged in as a user in the administrator role And There are 3 vendors When I go to the manage vendors page Then I should see the first 3 vendor names

$this->given("I am logged in as a user in the (.*) role", function($browser, $matches) { $browser->get('/') ->with('form')->begin() ->fill('login_'.$matches[1]) ->end() ->click('Sign in') ; });

Wednesday, January 6, 2010