Test Driven Development (TDD) involves writing tests before writing code to ensure features work as intended. The document discusses:
1. The TDD process of writing a failing test, writing code to pass the test, and refactoring code and rerunning tests.
2. Benefits of TDD like detecting defects early, code that works as intended, and tests as documentation.
3. EcomDev_PHPUnit, a library that makes it easy to write isolated, data-driven, and integration tests for Magento modules.
4. Examples of different types of tests like models, controllers, layouts, configurations, and more.
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
TDD Practices for Magento Using EcomDev PHPUnit
1. Using of Test Driven DevelopmentPractices for Magento Ivan Chepurnyi Magento Trainer / Lead Developer
2. Short Overview Meet Magento Netherlands Write a test Imaging how your feature should work and write a failing test Write feature quickly for receiving passed test Refactor your code and run the test again Pass Run the tests Fail Pass Write the code Fail Run the tests
3. Conventional Development Meet Magento Netherlands You need to write a full functionality for seeing the result You think that your code works Debugging With every fixed issue you may produce a new one Even if you write unit tests after implementation it doesn’t guarantee that you detect the defect.
4. Test Driven Development Meet Magento Netherlands You don’t need to implement full functionality for seeing the result Your colleagues can use your test as learning material The test proofs that your code works and can be verified Serious defects can be fixed on early state
5. Defect Costs Meet Magento Netherlands Percentage from project development hours < 1% 20% > 40% Defect found at the coding stage Defect found during QA phase Defect found after going live
6. Type of Tests Meet Magento Netherlands Automated Test Regression Test Learning Test Integration Test
7. Meet Magento Netherlands Test in Isolation Make test simple Test erroneous situations Test Doubles (Fake heavy resources you don’t depend on) Main Principles
8. EcomDev_PHPUnit Meet Magento Netherlands Making possible isolation of your test Easy test data loading via Yaml fixtures Data providers and expectations for reusable tests Easy way of testing configuration files Easy way for Layouts & Controllers integration test
9. Simple Test Case Meet Magento Netherlands class EcomDev_Example_Test_Model_Productextends EcomDev_PHPUnit_Test_Case { /** * @test * @loadFixture * @dataProviderdataProvider */ public function priceCalculation($productId, $storeId) { $storeId = Mage::app()->getStore($storeId)->getId(); $product = Mage::getModel('catalog/product') ->setStoreId($storeId) ->load($productId); $expected = $this->expected('%s-%s', $productId, $storeId); $this->assertEquals($expected->getFinalPrice(), $product->getFinalPrice()); $this->assertEquals($expected->getPrice(), $product->getPrice()); } } Test Case Class
10. Simple Test Case Meet Magento Netherlands eav: catalog_product: - entity_id: 1 type_id: simple sku: book website_ids: - usa_website - canada_website price: 12.99 status: 1 # Enabled visibility: 4 # Visible in Catalog & Search /websites: # Set different prices per website usa_website: special_price: 9.99 german_website: price: 9.99 special_price: 5.99 Yaml Fixture
12. Event Dispatch Check Meet Magento Netherlands class EcomDev_Example_Test_Model_Cms_Pageextends EcomDev_PHPUnit_Test_Case { // … public function testAvailableStatuses() { Mage::getModel(‘cms/page’)->getAvailableStatuses(); $this->assertEventDispatched( ‘cms_page_get_available_statuses’ ); } } Test Case
13. Test Doubles Meet Magento Netherlands class EcomDev_PHPUnit_Tes_Case_Controllerextends EcomDev_PHPUnit_Test_Case { protected function registerCookieStub() { $cookie = $this->getModelMock('core/cookie', array('set', 'delete')); $cookie->expects($this->any()) ->method('set') ->will($this->returnCallback(array($this, 'setCookieCallback‘))); $cookie->expects($this->any()) ->method('delete‘) ->will($this->returnCallback(array($this, 'deleteCookieCallback‘))); $this->replaceByMock('singleton', 'core/cookie', $cookie); return $this; } } Test Case
14. Config Test Case Meet Magento Netherlands class EcomDev_Example_Test_Config_Main extends EcomDev_PHPUnit_Test_Case_Config { //…. public function testModuleVersion() { $this->assertModuleCodePool('local'); $this->assertModuleDepends(‘Mage_Catalog’); $this->assertModuleVersionGreaterThan(‘0.1.0'); } } Testing Module Nodes
15. Config Test Case Meet Magento Netherlands class EcomDev_Example_Test_Config_Main extends EcomDev_PHPUnit_Test_Case_Config { //…. public function testClassAliasDefinitions() { $this->assertModelAlias('catalog/product', 'Mage_Catalog_Model_Product'); $this->assertResourceModelAlias( 'catalog/product', ‘Mage_Catalog_Model_Resource_Eav_Mysql4_Product‘ ); $this->assertBlockAlias( 'catalog/product_list', 'Mage_Catalog_Block_Product_List‘ ); } } Testing Class Aliases
16. Config Test Case Meet Magento Netherlands class EcomDev_Example_Test_Config_Main extends EcomDev_PHPUnit_Test_Case_Config { //…. public function testEventObservers() { $this->assertEventObserverDefined( 'frontend', 'customer_login', 'catalog/product_compare_item', 'bindCustomerLogin' ); } } Testing Event Observer Definitions
17. Controller Test Case Meet Magento Netherlands class EcomDev_Example_Test_Controller_Main extends EcomDev_PHPUnit_Test_Case_Controller { public function testRequest() { $this->dispatch('cms'); $this->assertRequestDispatched(); $this->assertRequestNotForwarded(); $this->assertRequestRoute('cms/index/index'); $this->assertRequestRouteName('cms'); $this->assertRequestControllerName('index'); $this->assertRequestControllerModule('Mage_Cms'); $this->assertRequestActionName('index'); } } Testing Request
18. Controller Test Case Meet Magento Netherlands class EcomDev_Example_Test_Controller_Main extends EcomDev_PHPUnit_Test_Case_Controller { public function testLayout() { $this->dispatch(''); $this->assertLayoutHandleLoaded('cms_index_index'); $this->assertLayoutBlockCreated('right'); $this->assertLayoutBlockRendered('content'); $this->assertLayoutBlockActionNotInvoked( 'footer_links', 'addLink', '', array('Custom Title') ); $this->assertLayoutBlockActionInvokedAtLeast( 'footer_links', 'addLink', 4, '‘ ); } } Testing Layouts
19. What’s Next Meet Magento Netherlands Write automated tests for your moduleshttp://www.magentocommerce.com/magento-connect/Ecommerce%20Developers/extension/5717/ecomdev_phpunit Keep project healthy during its lifecycle with Continuous Integration Running Daily Builds Running Unit Tests in 10 minutes after last commit Hudson http://hudson-ci.org phpUnderControlhttp://phpundercontrol.org/