Your SlideShare is downloading. ×
Nashville Symfony Functional Testing
Upcoming SlideShare
Loading in...5

Thanks for flagging this SlideShare!

Oops! An error has occurred.


Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

Nashville Symfony Functional Testing


Published on

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

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

Published in: Technology, Business

  • Be the first to comment

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

No notes for slide


  • 1. 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
  • 2. 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
  • 3. TOOLS FOR FUNCTIONAL TESTING Cucumber “Cucumber is designed to allow you to execute feature documentation written in plain text (often known as ‘stories’).” •We will discuss this later 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 Wednesday, January 6, 2010
  • 4. FUNCTIONAL TESTING IN SYMFONY - 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 Wednesday, January 6, 2010
  • 5. EXTEND THE TEST FRAMEWORK Subclass 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
  • 6. USE FIXTURES // test/data/urls.yml - url: /blog Create a YAML file to hold module: blog action: index statusCode: 200 data - url: /blog/new module: blog action: new AND... statusCode: 200 - url: /blog/edit module: blog action: edit Simplify Repetitive Tests! 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']) ; } Wednesday, January 6, 2010
  • 7. CREATE YOUR OWN TESTER Extend 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
  • 8. Extend sfTesterForm (continued) // test/data/forms.yml login_bad: signin: username: admin password: wrongpassword login: signin: Create Form Fixtures username: admin password: rightpassword login2: signin[username]: admin signin[password]: rightpassword Load them into your Tester! // lib/test/csTesterForm.class.php public 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')); } } // test/functional/backend/loginTest.php $browser = new csTestFunctional(new sfBrowser(), null, array('form' => 'csTesterForm')); Instantiate Your Classes Wednesday, January 6, 2010
  • 9. USE FACTORIES Helpful 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
  • 10. PUTTING IT ALL TOGETHER $browser = new csTestFunctional(new sfBrowser(), null, array('form' => 'csTesterForm', 'doctrine' => 'sfTesterDoctrine')); $browser->info('Create a new Company'); Initialize your testers $browser ->login() ->get('/company/new') ->with('form')->begin() ->fill('company', array('company[name]' => sfFactory::generate('Company'))) ->end() Fill the form with a ->info('Create Company "'.sfFactory::last().'"') unique value ->click('Save and add') ->with('form')->begin() ->hasErrors(false) ->end() ->followRedirect() Verify record exists ->with('doctrine')->begin() ->check('Company', array('name' => sfFactory::last())) ->end() ; Wednesday, January 6, 2010
  • 11. Success! Wednesday, January 6, 2010
  • 12. CAN YOU THINK OF OTHER USEFUL TESTERS? Wednesday, January 6, 2010
  • 13. USE PLUGINS swFunctionalTestGenerationPlugin Add to your dev toolbar Quickly stub symfony functional tests while clicking through the browser Wednesday, January 6, 2010
  • 14. SO YOU WANNA TEST YOUR PLUGINS? sfTaskExtraPlugin $ ./symfony generate:plugin sfScraperPlugin --module=sfScraper --test-application=frontend Plugin Skeleton Test Fixtures Wednesday, January 6, 2010
  • 15. sfTaskExtraPlugin (continued) Run all plugin tests $ ./symfony test:plugin sfScraperPlugin Connect plugin tests in ProjectConfiguration and.... // config/ProjectConfiguration.class.php public function setupPlugins() { $this->pluginConfigurations['sfScraperPlugin']->connectTests(); } Run plugin tests alongside project tests $ ./symfony test:all Run tests individually $ ./symfony test:unit sfScraper $ ./symfony test:functional frontend sfScraperActions Wednesday, January 6, 2010
  • 16. A LITTLE TASTE OF CUCUMBER Scenario: See all vendors Uses “Scenarios” 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 that are then $this->given("I am logged in as a user in the (.*) role", function($browser, $matches) { $browser->get('/') interpreted using ->with('form')->begin() ->fill('login_'.$matches[1]) ->end() “Steps” ; }); ->click('Sign in') Wednesday, January 6, 2010
  • 17. CHECK OUT MORE Selenium plugin to integrate with Symfony - • Cucumber - • Poocumber! - • Presentation Notes - 2010-02-05-FunctionalTesting Wednesday, January 6, 2010
  • 18. CONTACT Brent Shaffer Wednesday, January 6, 2010