Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Quality Assurance in Magento

Quality Assurance in Magento

MageTest unit and functional testing module for use with Magento. Delivered at Magento Imagine 2011

Alistair Stead

October 08, 2011
Tweet

More Decks by Alistair Stead

Other Decks in Programming

Transcript

  1. WHO AM I • Alistair Stead • Technical Team Lead

    @ Ibuildings UK / Session Digital • Lead Magento projects for 3663, WMI, Kookai and others • Over 3 years experience with Magento • Zend Certified Engineer • Over 11 years commercial experience developing in PHP Wednesday, 9 February 2011
  2. With whom should the BUCK stop? Lets make sure its

    not us.... Wednesday, 9 February 2011
  3. <?php /** * Magento PHPUnit TestCase * * @package Ibuildings_Mage_Test_PHPUnit

    * @copyright Copyright (c) 2011 Ibuildings. (http://www.ibuildings.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * @author Alistair Stead <[email protected]> * @version $Id$ */ /** * PHPUnit_Framework_Magento_TestCase * * @category Mage_Test * @package Ibuildings_Mage_Test_PHPUnit * @subpackage Ibuildings_Mage_Test_PHPUnit_TestCase * @uses PHPUnit_Framework_TestCase */ abstract class Ibuildings_Mage_Test_PHPUnit_TestCase extends PHPUnit_Framework_TestCase { public function setUp() { parent::setUp(); // Initialise Magento Mage::app(); } } Wednesday, 9 February 2011
  4. <?php /** * Magento PHPUnit TestCase * * @package Ibuildings_Mage_Test_PHPUnit

    * @copyright Copyright (c) 2011 Ibuildings. (http://www.ibuildings.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * @author Alistair Stead <[email protected]> * @version $Id$ */ /** * PHPUnit_Framework_Magento_TestCase * * @category Mage_Test * @package Ibuildings_Mage_Test_PHPUnit * @subpackage Ibuildings_Mage_Test_PHPUnit_TestCase * @uses PHPUnit_Framework_TestCase */ abstract class Ibuildings_Mage_Test_PHPUnit_TestCase extends PHPUnit_Framework_TestCase { public function setUp() { parent::setUp(); // Initialise Magento Mage::app(); } } Wednesday, 9 February 2011
  5. <?php class DataCash_Dpg_Model_ConfigTest extends Ibuildings_Mage_Test_PHPUnit_TestCase { /** * Member variable

    to hold reference to the opbject under test * * @var DataCash_Dpg_Model_Config **/ protected $_object; /** * Setup fixtures and dependencies * * @return void * @author Alistair Stead **/ public function setUp() { parent::setUp(); $this->_object = Mage::getSingleton('dpg/config'); } Wednesday, 9 February 2011
  6. <?php class DataCash_Dpg_Model_ConfigTest extends Ibuildings_Mage_Test_PHPUnit_TestCase { /** * Member variable

    to hold reference to the opbject under test * * @var DataCash_Dpg_Model_Config **/ protected $_object; /** * Setup fixtures and dependencies * * @return void * @author Alistair Stead **/ public function setUp() { parent::setUp(); $this->_object = Mage::getSingleton('dpg/config'); } Wednesday, 9 February 2011
  7. <?php class DataCash_Dpg_Model_ConfigTest extends Ibuildings_Mage_Test_PHPUnit_TestCase { /** * Member variable

    to hold reference to the opbject under test * * @var DataCash_Dpg_Model_Config **/ protected $_object; /** * Setup fixtures and dependencies * * @return void * @author Alistair Stead **/ public function setUp() { parent::setUp(); $this->_object = Mage::getSingleton('dpg/config'); } Wednesday, 9 February 2011
  8. /** * mageSingletonFactoryReturnsExpectedObject * @author Alistair Stead * @test */

    public function mageSingletonFactoryReturnsExpectedObject() { $this->assertInstanceOf('DataCash_Dpg_Model_Config', $this->_object, 'Unexpected object returned by factory'); } // mageSingletonFactoryReturnsExpectedObject /** * mageSingletonFactoryReturnsTheSameObject * @author Alistair Stead * @test */ public function mageSingletonFactoryReturnsTheSameObject() { $this->assertSame($this->_object, Mage::getSingleton('dpg/config'), 'Two different objects have been created'); } // mageSingletonFactoryReturnsTheSameObject Wednesday, 9 February 2011
  9. /** * mageSingletonFactoryReturnsExpectedObject * @author Alistair Stead * @test */

    public function mageSingletonFactoryReturnsExpectedObject() { $this->assertInstanceOf('DataCash_Dpg_Model_Config', $this->_object, 'Unexpected object returned by factory'); } // mageSingletonFactoryReturnsExpectedObject /** * mageSingletonFactoryReturnsTheSameObject * @author Alistair Stead * @test */ public function mageSingletonFactoryReturnsTheSameObject() { $this->assertSame($this->_object, Mage::getSingleton('dpg/config'), 'Two different objects have been created'); } // mageSingletonFactoryReturnsTheSameObject Wednesday, 9 February 2011
  10. /** * mageSingletonFactoryReturnsExpectedObject * @author Alistair Stead * @test */

    public function mageSingletonFactoryReturnsExpectedObject() { $this->assertInstanceOf('DataCash_Dpg_Model_Config', $this->_object, 'Unexpected object returned by factory'); } // mageSingletonFactoryReturnsExpectedObject /** * mageSingletonFactoryReturnsTheSameObject * @author Alistair Stead * @test */ public function mageSingletonFactoryReturnsTheSameObject() { $this->assertSame($this->_object, Mage::getSingleton('dpg/config'), 'Two different objects have been created'); } // mageSingletonFactoryReturnsTheSameObject Wednesday, 9 February 2011
  11. /** * getTransactionTypesReturnsArray * @author Alistair Stead * @test */

    public function getTransactionTypesReturnsArray() { $result = $this->_object->getTansactionTypes(); $this->assertTrue(is_array($result), 'No array returned'); $this->assertEquals(count($result), 2, 'More transaction types than expected'); $this->assertArrayHasKey( 'A', $result, 'The array does not contain A' ); $this->assertArrayHasKey( 'P', $result, 'The array does not contain P' ); } // getTransactionTypesReturnsArray Wednesday, 9 February 2011
  12. /** * getTransactionTypesReturnsArray * @author Alistair Stead * @test */

    public function getTransactionTypesReturnsArray() { $result = $this->_object->getTansactionTypes(); $this->assertTrue(is_array($result), 'No array returned'); $this->assertEquals(count($result), 2, 'More transaction types than expected'); $this->assertArrayHasKey( 'A', $result, 'The array does not contain A' ); $this->assertArrayHasKey( 'P', $result, 'The array does not contain P' ); } // getTransactionTypesReturnsArray Wednesday, 9 February 2011
  13. /** * Setup fixtures and dependencies * * @return void

    * @author Alistair Stead **/ public function setUp() { parent::setUp(); $this->_helper = Mage::helper('contactsdepartment'); $this->_departmentIds = array(); $department = Mage::getModel('contactsdepartment/department'); $fixtures = array( array( 'department_name' => 'department one', 'department_email' => '[email protected]', 'store_id' => 0 ) ); foreach ($fixtures as $data) { $department->addData($data); $department->save(); $this->_departmentIds[] = $department->getId(); } } Wednesday, 9 February 2011
  14. /** * Setup fixtures and dependencies * * @return void

    * @author Alistair Stead **/ public function setUp() { parent::setUp(); $this->_helper = Mage::helper('contactsdepartment'); $this->_departmentIds = array(); $department = Mage::getModel('contactsdepartment/department'); $fixtures = array( array( 'department_name' => 'department one', 'department_email' => '[email protected]', 'store_id' => 0 ) ); foreach ($fixtures as $data) { $department->addData($data); $department->save(); $this->_departmentIds[] = $department->getId(); } } Wednesday, 9 February 2011
  15. /** * Setup fixtures and dependencies * * @return void

    * @author Alistair Stead **/ public function setUp() { parent::setUp(); $this->_helper = Mage::helper('contactsdepartment'); $this->_departmentIds = array(); $department = Mage::getModel('contactsdepartment/department'); $fixtures = array( array( 'department_name' => 'department one', 'department_email' => '[email protected]', 'store_id' => 0 ) ); foreach ($fixtures as $data) { $department->addData($data); $department->save(); $this->_departmentIds[] = $department->getId(); } } Wednesday, 9 February 2011
  16. /** * helperFactoryReturnsTheExpectedClass * @author Alistair Stead * @test */

    public function helperFactoryReturnsTheExpectedClass() { $this->assertInstanceOf('Ibuildings_ContactsDepartment_Helper_Data', $this->_helper); } // helperFactoryReturnsTheExpectedClass /** * getDepartmentOptionsShouldReturnAssociativeArray * @author Alistair Stead * @test */ public function getDepartmentOptionsShouldReturnAssociativeArray() { foreach ($this->_helper->getDepartmentOptions() as $option) { $this->assertArrayHasKey( 'value', $option, 'The options array does not have a value' ); $this->assertArrayHasKey( 'label', $option, 'The options array does not have a label' ); } } // getDepartmentOptionsShouldReturnAssociativeArray Wednesday, 9 February 2011
  17. /** * helperFactoryReturnsTheExpectedClass * @author Alistair Stead * @test */

    public function helperFactoryReturnsTheExpectedClass() { $this->assertInstanceOf('Ibuildings_ContactsDepartment_Helper_Data', $this->_helper); } // helperFactoryReturnsTheExpectedClass /** * getDepartmentOptionsShouldReturnAssociativeArray * @author Alistair Stead * @test */ public function getDepartmentOptionsShouldReturnAssociativeArray() { foreach ($this->_helper->getDepartmentOptions() as $option) { $this->assertArrayHasKey( 'value', $option, 'The options array does not have a value' ); $this->assertArrayHasKey( 'label', $option, 'The options array does not have a label' ); } } // getDepartmentOptionsShouldReturnAssociativeArray Wednesday, 9 February 2011
  18. /** * helperFactoryReturnsTheExpectedClass * @author Alistair Stead * @test */

    public function helperFactoryReturnsTheExpectedClass() { $this->assertInstanceOf('Ibuildings_ContactsDepartment_Helper_Data', $this->_helper); } // helperFactoryReturnsTheExpectedClass /** * getDepartmentOptionsShouldReturnAssociativeArray * @author Alistair Stead * @test */ public function getDepartmentOptionsShouldReturnAssociativeArray() { foreach ($this->_helper->getDepartmentOptions() as $option) { $this->assertArrayHasKey( 'value', $option, 'The options array does not have a value' ); $this->assertArrayHasKey( 'label', $option, 'The options array does not have a label' ); } } // getDepartmentOptionsShouldReturnAssociativeArray Wednesday, 9 February 2011
  19. /** * Provide a public method to allow the internal

    Request object * to be set at runtime. This can be used to inject a testing request object * * @return void * @author Alistair Stead **/ public function setRequest(Zend_Controller_Request_Abstract $request) { $this->_request = $request; } /** * Retrieve request object * * @return Mage_Core_Controller_Request_Http */ public function getRequest() { if (empty($this->_request)) { $this->_request = new Mage_Core_Controller_Request_Http(); } return $this->_request; } Wednesday, 9 February 2011
  20. /** * Provide a public method to allow the internal

    Request object * to be set at runtime. This can be used to inject a testing request object * * @return void * @author Alistair Stead **/ public function setRequest(Zend_Controller_Request_Abstract $request) { $this->_request = $request; } /** * Retrieve request object * * @return Mage_Core_Controller_Request_Http */ public function getRequest() { if (empty($this->_request)) { $this->_request = new Mage_Core_Controller_Request_Http(); } return $this->_request; } Wednesday, 9 February 2011
  21. /** * Provide a public method to allow the protected

    internal Response object * to be set at runtime. This can be used to inject a testing response object * * @return void * @author Alistair Stead **/ public function setResponse(Zend_Controller_Response_Abstract $response) { $this->_response = $response; } /** * Retrieve response object * * @return Zend_Controller_Response_Http */ public function getResponse() { if (empty($this->_response)) { $this->_response = new Mage_Core_Controller_Response_Http(); $this->_response->headersSentThrowsException = Mage::$headersSentThrowsException; $this->_response->setHeader("Content-Type", "text/html; charset=UTF-8"); } return $this->_response; } Wednesday, 9 February 2011
  22. /** * Provide a public method to allow the protected

    internal Response object * to be set at runtime. This can be used to inject a testing response object * * @return void * @author Alistair Stead **/ public function setResponse(Zend_Controller_Response_Abstract $response) { $this->_response = $response; } /** * Retrieve response object * * @return Zend_Controller_Response_Http */ public function getResponse() { if (empty($this->_response)) { $this->_response = new Mage_Core_Controller_Response_Http(); $this->_response->headersSentThrowsException = Mage::$headersSentThrowsException; $this->_response->setHeader("Content-Type", "text/html; charset=UTF-8"); } return $this->_response; } Wednesday, 9 February 2011
  23. /** * Bootstrap the Mage application in a similar way

    to the procedure * of index.php * * Then sets test case request and response objects in Mage_Core_App, * and disables returning the response. * * @return void * @author Alistair Stead */ public function mageBootstrap() { Mage::reset(); if (isset($_SERVER['MAGE_IS_DEVELOPER_MODE'])) { Mage::setIsDeveloperMode(true); } // Store or website code $this->mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : ''; // Run store or run website $this->mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store'; // Initialize the Mage App and inject the testing request & response Mage::app($this->mageRunCode, $this->mageRunType, $this->options); Mage::app()->setRequest(new Ibuildings_Mage_Controller_Request_HttpTestCase); Mage::app()->setResponse(new Ibuildings_Mage_Controller_Response_HttpTestCase); } Wednesday, 9 February 2011
  24. /** * Bootstrap the Mage application in a similar way

    to the procedure * of index.php * * Then sets test case request and response objects in Mage_Core_App, * and disables returning the response. * * @return void * @author Alistair Stead */ public function mageBootstrap() { Mage::reset(); if (isset($_SERVER['MAGE_IS_DEVELOPER_MODE'])) { Mage::setIsDeveloperMode(true); } // Store or website code $this->mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : ''; // Run store or run website $this->mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store'; // Initialize the Mage App and inject the testing request & response Mage::app($this->mageRunCode, $this->mageRunType, $this->options); Mage::app()->setRequest(new Ibuildings_Mage_Controller_Request_HttpTestCase); Mage::app()->setResponse(new Ibuildings_Mage_Controller_Response_HttpTestCase); } Wednesday, 9 February 2011
  25. /** * Bootstrap the Mage application in a similar way

    to the procedure * of index.php * * Then sets test case request and response objects in Mage_Core_App, * and disables returning the response. * * @return void * @author Alistair Stead */ public function mageBootstrap() { Mage::reset(); if (isset($_SERVER['MAGE_IS_DEVELOPER_MODE'])) { Mage::setIsDeveloperMode(true); } // Store or website code $this->mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : ''; // Run store or run website $this->mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store'; // Initialize the Mage App and inject the testing request & response Mage::app($this->mageRunCode, $this->mageRunType, $this->options); Mage::app()->setRequest(new Ibuildings_Mage_Controller_Request_HttpTestCase); Mage::app()->setResponse(new Ibuildings_Mage_Controller_Response_HttpTestCase); } Wednesday, 9 February 2011
  26. <?php /** * Mage_Catalog_IndexControllerTest * * @package Mage_Catalog * @subpackage

    Mage_Catalog_Test * * * @uses PHPUnit_Framework_Magento_TestCase */ class Mage_Catalog_IndexControllerTest extends Ibuildings_Mage_Test_PHPUnit_ControllerTestCase { /** * theIndexActionShouldRedirectToRoot * @author Alistair Stead * @test */ public function theIndexActionShouldRedirectToRoot() { $this->dispatch('/'); $this->assertRoute('cms', "The expected cms route has not been matched"); $this->assertAction('index', "The index action has not been called"); $this->assertController('index', "The expected controller is not been used"); $this->assertQuery('div.nav-container', 'The site navigation is not present on the home page'); } // theIndexActionShouldRedirectToRoot } Wednesday, 9 February 2011
  27. <?php /** * Mage_Catalog_IndexControllerTest * * @package Mage_Catalog * @subpackage

    Mage_Catalog_Test * * * @uses PHPUnit_Framework_Magento_TestCase */ class Mage_Catalog_IndexControllerTest extends Ibuildings_Mage_Test_PHPUnit_ControllerTestCase { /** * theIndexActionShouldRedirectToRoot * @author Alistair Stead * @test */ public function theIndexActionShouldRedirectToRoot() { $this->dispatch('/'); $this->assertRoute('cms', "The expected cms route has not been matched"); $this->assertAction('index', "The index action has not been called"); $this->assertController('index', "The expected controller is not been used"); $this->assertQuery('div.nav-container', 'The site navigation is not present on the home page'); } // theIndexActionShouldRedirectToRoot } Wednesday, 9 February 2011
  28. <?php /** * Mage_Catalog_IndexControllerTest * * @package Mage_Catalog * @subpackage

    Mage_Catalog_Test * * * @uses PHPUnit_Framework_Magento_TestCase */ class Mage_Catalog_IndexControllerTest extends Ibuildings_Mage_Test_PHPUnit_ControllerTestCase { /** * theIndexActionShouldRedirectToRoot * @author Alistair Stead * @test */ public function theIndexActionShouldRedirectToRoot() { $this->dispatch('/'); $this->assertRoute('cms', "The expected cms route has not been matched"); $this->assertAction('index', "The index action has not been called"); $this->assertController('index', "The expected controller is not been used"); $this->assertQuery('div.nav-container', 'The site navigation is not present on the home page'); } // theIndexActionShouldRedirectToRoot } Wednesday, 9 February 2011
  29. /** * theAdminRouteAccessesTheAdminApplicationArea * @author Alistair Stead * @test */

    public function theAdminRouteAccessesTheAdminApplicationArea() { $this->dispatch('admin/'); $this->assertRoute('adminhtml', "The expected route has not been matched"); $this->assertAction('login', "The login form should be presented"); $this->assertController('index', "The expected controller is not been used"); } // theAdminRouteAccessesTheAdminApplicationArea /** * theIndexActionDisplaysLoginForm * @author Alistair Stead * @group login * @test */ public function theIndexActionDisplaysLoginForm() { $this->dispatch('admin/index/'); $this->assertQueryCount('form#loginForm', 1); } // theIndexActionDisplaysLoginForm Wednesday, 9 February 2011
  30. /** * theAdminRouteAccessesTheAdminApplicationArea * @author Alistair Stead * @test */

    public function theAdminRouteAccessesTheAdminApplicationArea() { $this->dispatch('admin/'); $this->assertRoute('adminhtml', "The expected route has not been matched"); $this->assertAction('login', "The login form should be presented"); $this->assertController('index', "The expected controller is not been used"); } // theAdminRouteAccessesTheAdminApplicationArea /** * theIndexActionDisplaysLoginForm * @author Alistair Stead * @group login * @test */ public function theIndexActionDisplaysLoginForm() { $this->dispatch('admin/index/'); $this->assertQueryCount('form#loginForm', 1); } // theIndexActionDisplaysLoginForm Wednesday, 9 February 2011
  31. /** * theAdminRouteAccessesTheAdminApplicationArea * @author Alistair Stead * @test */

    public function theAdminRouteAccessesTheAdminApplicationArea() { $this->dispatch('admin/'); $this->assertRoute('adminhtml', "The expected route has not been matched"); $this->assertAction('login', "The login form should be presented"); $this->assertController('index', "The expected controller is not been used"); } // theAdminRouteAccessesTheAdminApplicationArea /** * theIndexActionDisplaysLoginForm * @author Alistair Stead * @group login * @test */ public function theIndexActionDisplaysLoginForm() { $this->dispatch('admin/index/'); $this->assertQueryCount('form#loginForm', 1); } // theIndexActionDisplaysLoginForm Wednesday, 9 February 2011
  32. /** * theAdminRouteAccessesTheAdminApplicationArea * @author Alistair Stead * @test */

    public function theAdminRouteAccessesTheAdminApplicationArea() { $this->dispatch('admin/'); $this->assertRoute('adminhtml', "The expected route has not been matched"); $this->assertAction('login', "The login form should be presented"); $this->assertController('index', "The expected controller is not been used"); } // theAdminRouteAccessesTheAdminApplicationArea /** * theIndexActionDisplaysLoginForm * @author Alistair Stead * @group login * @test */ public function theIndexActionDisplaysLoginForm() { $this->dispatch('admin/index/'); $this->assertQueryCount('form#loginForm', 1); } // theIndexActionDisplaysLoginForm Wednesday, 9 February 2011
  33. /** * theAdminRouteAccessesTheAdminApplicationArea * @author Alistair Stead * @test */

    public function theAdminRouteAccessesTheAdminApplicationArea() { $this->dispatch('admin/'); $this->assertRoute('adminhtml', "The expected route has not been matched"); $this->assertAction('login', "The login form should be presented"); $this->assertController('index', "The expected controller is not been used"); } // theAdminRouteAccessesTheAdminApplicationArea /** * theIndexActionDisplaysLoginForm * @author Alistair Stead * @group login * @test */ public function theIndexActionDisplaysLoginForm() { $this->dispatch('admin/index/'); $this->assertQueryCount('form#loginForm', 1); } // theIndexActionDisplaysLoginForm Wednesday, 9 February 2011
  34. /** * submittingInvalidCredsShouldDisplayError * @author Alistair Stead * @group login

    * @test */ public function submittingInvalidCredsShouldDisplayError() { $this->request->setMethod('POST') ->setPost( array( 'login' => array( 'username' => 'admin', 'password' => 'invalid-password', ) ) ); $this->dispatch('admin/index/login'); $this->assertQueryCount('li.error-msg', 1); $this->assertQueryContentContains('li.error-msg', 'Invalid Username or Password.'); } // submittingInvalidCredsShouldDisplayError Wednesday, 9 February 2011
  35. /** * submittingInvalidCredsShouldDisplayError * @author Alistair Stead * @group login

    * @test */ public function submittingInvalidCredsShouldDisplayError() { $this->request->setMethod('POST') ->setPost( array( 'login' => array( 'username' => 'admin', 'password' => 'invalid-password', ) ) ); $this->dispatch('admin/index/login'); $this->assertQueryCount('li.error-msg', 1); $this->assertQueryContentContains('li.error-msg', 'Invalid Username or Password.'); } // submittingInvalidCredsShouldDisplayError Wednesday, 9 February 2011
  36. /** * submittingInvalidCredsShouldDisplayError * @author Alistair Stead * @group login

    * @test */ public function submittingInvalidCredsShouldDisplayError() { $this->request->setMethod('POST') ->setPost( array( 'login' => array( 'username' => 'admin', 'password' => 'invalid-password', ) ) ); $this->dispatch('admin/index/login'); $this->assertQueryCount('li.error-msg', 1); $this->assertQueryContentContains('li.error-msg', 'Invalid Username or Password.'); } // submittingInvalidCredsShouldDisplayError Wednesday, 9 February 2011
  37. /** * submittingInvalidCredsShouldDisplayError * @author Alistair Stead * @group login

    * @test */ public function submittingInvalidCredsShouldDisplayError() { $this->request->setMethod('POST') ->setPost( array( 'login' => array( 'username' => 'admin', 'password' => 'invalid-password', ) ) ); $this->dispatch('admin/index/login'); $this->assertQueryCount('li.error-msg', 1); $this->assertQueryContentContains('li.error-msg', 'Invalid Username or Password.'); } // submittingInvalidCredsShouldDisplayError Wednesday, 9 February 2011
  38. /** * submittingInvalidCredsShouldDisplayError * @author Alistair Stead * @group login

    * @test */ public function submittingInvalidCredsShouldDisplayError() { $this->request->setMethod('POST') ->setPost( array( 'login' => array( 'username' => 'admin', 'password' => 'invalid-password', ) ) ); $this->dispatch('admin/index/login'); $this->assertQueryCount('li.error-msg', 1); $this->assertQueryContentContains('li.error-msg', 'Invalid Username or Password.'); } // submittingInvalidCredsShouldDisplayError Wednesday, 9 February 2011
  39. /** * submittingValidCredsShouldDisplayDashboard * @author Alistair Stead * @group login

    * @test */ public function submittingValidCredsShouldDisplayDashboard() { $this->request->setMethod('POST') ->setPost( array( 'login' => array( 'username' => 'admin', 'password' => '123456', ) ) ); $this->dispatch('admin/index/login'); $this->assertRedirect('We should be redirected after login'); $this->assertRedirectRegex("/^.*dashboard.*$/", 'We are not directed to the dashboard'); } // submittingValidCredsShouldDisplayDashboard Wednesday, 9 February 2011
  40. /** * submittingValidCredsShouldDisplayDashboard * @author Alistair Stead * @group login

    * @test */ public function submittingValidCredsShouldDisplayDashboard() { $this->request->setMethod('POST') ->setPost( array( 'login' => array( 'username' => 'admin', 'password' => '123456', ) ) ); $this->dispatch('admin/index/login'); $this->assertRedirect('We should be redirected after login'); $this->assertRedirectRegex("/^.*dashboard.*$/", 'We are not directed to the dashboard'); } // submittingValidCredsShouldDisplayDashboard Wednesday, 9 February 2011
  41. class Mage_Adminhtml_SalesControllerTest extends Mage_Adminhtml_ControllerTestCase { /** * indexActionListsOrders * @author

    Alistair Stead * @test */ public function indexActionListsOrders() { $this->request->setMethod('POST') ->setPost( array( 'login' => array( 'username' => 'admin', 'password' => '123456', ) ) ); $this->dispatch('admin/index/login'); // Reset the requests after login before next dispatch $this->reset(); $this->dispatch('admin/sales_order/index'); $this->assertQueryContentContains('h3.icon-head', 'Orders'); } // indexActionListsOrders } Wednesday, 9 February 2011
  42. class Mage_Adminhtml_SalesControllerTest extends Mage_Adminhtml_ControllerTestCase { /** * indexActionListsOrders * @author

    Alistair Stead * @test */ public function indexActionListsOrders() { $this->request->setMethod('POST') ->setPost( array( 'login' => array( 'username' => 'admin', 'password' => '123456', ) ) ); $this->dispatch('admin/index/login'); // Reset the requests after login before next dispatch $this->reset(); $this->dispatch('admin/sales_order/index'); $this->assertQueryContentContains('h3.icon-head', 'Orders'); } // indexActionListsOrders } Wednesday, 9 February 2011
  43. class Mage_Adminhtml_SalesControllerTest extends Mage_Adminhtml_ControllerTestCase { /** * indexActionListsOrders * @author

    Alistair Stead * @test */ public function indexActionListsOrders() { $this->request->setMethod('POST') ->setPost( array( 'login' => array( 'username' => 'admin', 'password' => '123456', ) ) ); $this->dispatch('admin/index/login'); // Reset the requests after login before next dispatch $this->reset(); $this->dispatch('admin/sales_order/index'); $this->assertQueryContentContains('h3.icon-head', 'Orders'); } // indexActionListsOrders } Wednesday, 9 February 2011
  44. public function mageBootstrap() { Mage::reset(); if (isset($_SERVER['MAGE_IS_DEVELOPER_MODE'])) { Mage::setIsDeveloperMode(true); }

    // Store or website code $this->mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : ''; // Run store or run website $this->mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store'; // Initialize the Mage App and inject the testing request & response Mage::app($this->mageRunCode, $this->mageRunType, $this->options); Mage::app()->setRequest(new Ibuildings_Mage_Controller_Request_HttpTestCase); Mage::app()->setResponse(new Ibuildings_Mage_Controller_Response_HttpTestCase); // Rewrite the core classes at runtime to prevent emails from being sent Mage::getConfig()->setNode('global/models/core/rewrite/email_template', 'Ibuildings_Test_Model_Email_Template'); // This is a hack to get the runtime config changes to take effect Mage::getModel('core/email_template'); } Wednesday, 9 February 2011
  45. public function mageBootstrap() { Mage::reset(); if (isset($_SERVER['MAGE_IS_DEVELOPER_MODE'])) { Mage::setIsDeveloperMode(true); }

    // Store or website code $this->mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : ''; // Run store or run website $this->mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store'; // Initialize the Mage App and inject the testing request & response Mage::app($this->mageRunCode, $this->mageRunType, $this->options); Mage::app()->setRequest(new Ibuildings_Mage_Controller_Request_HttpTestCase); Mage::app()->setResponse(new Ibuildings_Mage_Controller_Response_HttpTestCase); // Rewrite the core classes at runtime to prevent emails from being sent Mage::getConfig()->setNode('global/models/core/rewrite/email_template', 'Ibuildings_Test_Model_Email_Template'); // This is a hack to get the runtime config changes to take effect Mage::getModel('core/email_template'); } Wednesday, 9 February 2011
  46. /** * submittingForgotPasswordWithValidEmailReturnsSuccess * @author Alistair Stead * @group password

    * @test * */ public function submittingForgotPasswordWithValidEmailReturnsSuccess() { $this->request->setMethod('POST') ->setPost(array('email' => $this->email)); $this->dispatch('admin/index/forgotpassword/'); $this->assertQueryCount('li.success-msg', 1); $this->assertQueryContentContains('li.success-msg', 'A new password was sent to your email address. Please check your email and click Back to Login.'); // Test that the email contains the correct data $emailContent = $this->getResponseEmail() ->getBodyHtml() ->getContent(); // Overriding the response body to be able to use the standard content assertions $this->response->setBody($emailContent); // The email content addresses the fixture user $this->assertQueryContentContains('body', "Dear $this->firstName $this->lastName"); // The fixture users password has been changed $this->assertNotQueryContentContains('body', $this->password); } // submittingForgotPasswordWithValidEmailReturnsSuccess Wednesday, 9 February 2011
  47. /** * submittingForgotPasswordWithValidEmailReturnsSuccess * @author Alistair Stead * @group password

    * @test * */ public function submittingForgotPasswordWithValidEmailReturnsSuccess() { $this->request->setMethod('POST') ->setPost(array('email' => $this->email)); $this->dispatch('admin/index/forgotpassword/'); $this->assertQueryCount('li.success-msg', 1); $this->assertQueryContentContains('li.success-msg', 'A new password was sent to your email address. Please check your email and click Back to Login.'); // Test that the email contains the correct data $emailContent = $this->getResponseEmail() ->getBodyHtml() ->getContent(); // Overriding the response body to be able to use the standard content assertions $this->response->setBody($emailContent); // The email content addresses the fixture user $this->assertQueryContentContains('body', "Dear $this->firstName $this->lastName"); // The fixture users password has been changed $this->assertNotQueryContentContains('body', $this->password); } // submittingForgotPasswordWithValidEmailReturnsSuccess Wednesday, 9 February 2011
  48. /** * submittingForgotPasswordWithValidEmailReturnsSuccess * @author Alistair Stead * @group password

    * @test * */ public function submittingForgotPasswordWithValidEmailReturnsSuccess() { $this->request->setMethod('POST') ->setPost(array('email' => $this->email)); $this->dispatch('admin/index/forgotpassword/'); $this->assertQueryCount('li.success-msg', 1); $this->assertQueryContentContains('li.success-msg', 'A new password was sent to your email address. Please check your email and click Back to Login.'); // Test that the email contains the correct data $emailContent = $this->getResponseEmail() ->getBodyHtml() ->getContent(); // Overriding the response body to be able to use the standard content assertions $this->response->setBody($emailContent); // The email content addresses the fixture user $this->assertQueryContentContains('body', "Dear $this->firstName $this->lastName"); // The fixture users password has been changed $this->assertNotQueryContentContains('body', $this->password); } // submittingForgotPasswordWithValidEmailReturnsSuccess Wednesday, 9 February 2011
  49. /** * submittingForgotPasswordWithValidEmailReturnsSuccess * @author Alistair Stead * @group password

    * @test * */ public function submittingForgotPasswordWithValidEmailReturnsSuccess() { $this->request->setMethod('POST') ->setPost(array('email' => $this->email)); $this->dispatch('admin/index/forgotpassword/'); $this->assertQueryCount('li.success-msg', 1); $this->assertQueryContentContains('li.success-msg', 'A new password was sent to your email address. Please check your email and click Back to Login.'); // Test that the email contains the correct data $emailContent = $this->getResponseEmail() ->getBodyHtml() ->getContent(); // Overriding the response body to be able to use the standard content assertions $this->response->setBody($emailContent); // The email content addresses the fixture user $this->assertQueryContentContains('body', "Dear $this->firstName $this->lastName"); // The fixture users password has been changed $this->assertNotQueryContentContains('body', $this->password); } // submittingForgotPasswordWithValidEmailReturnsSuccess Wednesday, 9 February 2011
  50. MAGE-TEST IS OPEN SOURCE • Use Mage-Test to test your

    development projects • Use Mage-Test to test you extensions • Contribute tests for Magento • Build up the coverage of the Magento codebase • Take advantage of core tests for regression testing Wednesday, 9 February 2011
  51. REFERENCES • PHPUnit https://github.com/sebastianbergmann/phpunit/ • Zend_Test http://framework.zend.com/manual/en/ zend.test.html • Mage-Test

    https://github.com/ibuildings/Mage-Test • phpUnderControl http://phpundercontrol.org/ • Bamboo http://www.atlassian.com/software/bamboo/ Wednesday, 9 February 2011
  52. IMAGE CREDITS BA Plane: http://www.flickr.com/photos/bribri/1299325208/sizes/l/in/photostream/ Minions: http://www.akblessingsabound.com/wp-content/uploads/2010/06/despicable-me-minions- blessings-abound-mommy.jpg Eleventh Hour:

    http://www.flickr.com/photos/d4dee/2258343575/sizes/l/in/photostream/ Deep Thought: http://www.flickr.com/photos/8640416@N02/4213361072/sizes/l/in/photostream/ US Dollar: http://www.flickr.com/photos/8640416@N02/4213361072/sizes/l/in/photostream/ Whoa (Stop Sign): http://www.flickr.com/photos/aquaoracle/3265987824/sizes/l/ Departures Board: http://www.flickr.com/photos/scottmulhollan/4892422469/sizes/l/in/photostream/ Syringe: http://www.flickr.com/photos/woodypics/3809842998/sizes/z/in/photostream/ Coupled Carriages: http://www.flickr.com/photos/jowo/89657494/sizes/o/in/photostream/ Wednesday, 9 February 2011