SlideShare a Scribd company logo
Writing Testable Code
(for Magento 1 and 2)
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Assumptions
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
You know basic PHPUnit.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
You want
→ Confidence in deploys
→ Experience joy when writing tests
→ Have fun doing code maintaince
→ Get more $$$ from testing
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
In short, you want
→ Testable code
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
When is code
"testable"?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
When testing
is simple & easy.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
What makes a
test simple?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
It is simple to write.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
It is easy to read.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
What does
"easy to read"
mean?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
It's intent is clear.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
The test is short.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Good names.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
It only does
one thing.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Clean Code
is for
Production Code &
Test Code
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
What does
"simple to write"
mean?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Test code
depends on
production code
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
It are properties of the
production code
that make testing
easy or hard.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
"It's no big thing,
but you make big things
out of little things sometimes."
~~ Robert Duvall
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
What does easy to
test code look like?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
A bad case of legacy:
Event Observer
(for Magento 1)
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
<?php
use Varien_Event_Observer as Event;
class Netzarbeiter_CustomerActivation_Model_Observer
{
// Check if the customer has been activated, if not, throw login error
public function customerLogin(Event $event) {...}
// Flag new accounts as such
public function customerSaveBefore(Event $event) {...}
// Send out emails
public function customerSaveAfter(Event $event) {...}
// Abort registration during checkout if default activation status is false
public function salesConvertQuoteAddressToOrder(Event $event) {...}
// Add customer activation option to the mass action block
public function adminhtmlBlockHtmlBefore(Event $event) {...}
// Add the customer_activated attribute to the customer grid collection
public function eavCollectionAbstractLoadBefore(Event $event) {...}
// Add customer_activated column to CSV and XML exports
public function coreBlockAbstractPrepareLayoutAfter(Event $event) {...}
// Remove the customer id from the customer/session, in effect causing a logout
public function actionPostdispatchCustomerAccountResetPasswordPost(Event $event)
{...}
}
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Are we going to
write Unit Tests?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
For > 500 lines of legacy?
Hell NO!
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
What would make it
simpler to test?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
If the class where
smallerit would be simpler to test.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
First attempt:
Splitting the class based on
purpose.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
What does the
class do?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
1. Prevents inactive customer logins.
2. Sends notification emails.
3. Adds a column to the customer grid.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Lets split it into
Netzarbeiter_CustomerActivation_Model...
..._Observer_ProhibitInactiveLogins
..._Observer_EmailNotifications
..._Observer_AdminhtmlCustomerGrid
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
<?php
use Varien_Event_Observer as Event;
class Netzarbeiter_CustomerActivation_Model_Observer_ProhibitInactiveLogin
{
// Check if the customer has been activated, if not, throw login error
public function customerLogin(Event $event)
{...}
// Abort registration during checkout if default activation status is false
public function salesConvertQuoteAddressToOrder(Event $event)
{...}
// Remove the customer ID from the customer/session causing a logout
public function actionPostdispatchCustomerAccountResetPasswordPost(Event $event)
{...}
}
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
<?php
use Varien_Event_Observer as Event;
class Netzarbeiter_CustomerActivation_Model_Observer_EmailNotifications
{
// Flag new accounts as such
public function customerSaveBefore(Event $event)
{...}
// Send out emails
public function customerSaveAfter(Event $event)
{...}
}
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
<?php
use Varien_Event_Observer as Event;
class Netzarbeiter_CustomerActivation_Model_Observer_AdminhtmlCustomerGrid
{
// Add customer activation option to the mass action block
public function adminhtmlBlockHtmlBefore(Event $event)
{...}
// Add the customer_activated attribute to the customer grid collection
public function eavCollectionAbstractLoadBefore(Event $event)
{...}
// Add customer_activated column to CSV and XML exports
public function coreBlockAbstractPrepareLayoutAfter(Event $event)
{...}
}
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Is this simpler
to test?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Only minor difference in
testing effort.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Why?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
The same tests as before.
Only split into three classes.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Second attempt:
Lets go beyond
superficial changes.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Lets look at the design.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
What collaborators are used?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Collaborators:
Netzarbeiter_CustomerActivation_Helper_Data
Mage_Customer_Model_Customer
Mage_Customer_Model_Session
Mage_Customer_Model_Group
Mage_Customer_Helper_Address
Mage_Customer_Model_Resource_Customer_Collection
Mage_Core_Controller_Request_Http
Mage_Core_Controller_Response_Http
Mage_Core_Exception
Mage_Core_Model_Session
Mage_Core_Model_Store
Mage_Sales_Model_Quote_Address
Mage_Sales_Model_Quote
Mage_Eav_Model_Config
Mage_Eav_Model_Entity_Type
Mage_Adminhtml_Block_Widget_Grid_Massaction
Mage_Adminhtml_Block_Widget_Grid
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Almost all of them are core classes.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Only two classes are part of the module:
Netzarbeiter_CustomerActivation_Model_Observer
Netzarbeiter_CustomerActivation_Helper_Data
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Based on the names,
why do they exist?
Netzarbeiter_CustomerActivation_Model_Observer
Netzarbeiter_CustomerActivation_Helper_Data
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
The names don't
tell us anything.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Extract parts by giving them
meaningful names
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
But where to start?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Separate business logic
from the entry points.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Entry points are the places Magento
provides us to put our custom code.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Entry points:
→ Observers
→ Plugins
→ Controllers
→ Cron Jobs
→ Preferences
→ Console Commands
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Entry points link
Business logic
!
Magento
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Remove all
Business Logic
from
Entry Points.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
What are the
benefits?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
For testing:
The custom code can be triggered
independently of the entry point.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
In or example,
what is the
entry point?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Observer
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Old Observer Code:
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
public function customerLogin($observer)
{
$helper = Mage::helper('customeractivation');
if (!$helper->isModuleActive()) {
return;
}
if ($this->_isApiRequest()) {
return;
}
$customer = $observer->getEvent()->getCustomer();
$session = Mage::getSingleton('customer/session');
if (!$customer->getCustomerActivated()) {
$session->setCustomer(Mage::getModel('customer/customer'))
->setId(null)
->setCustomerGroupId(Mage_Customer_Model_Group::NOT_LOGGED_IN_ID);
if ($this->_checkRequestRoute('customer', 'account', 'createpost')) {
$message = $helper->__('Please wait for your account to be activated');
$session->addSuccess($message);
} else {
Mage::throwException($helper->__('This account is not activated.'));
}
}
}
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
New Code, without business logic:
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
public function customerLogin(Event $event)
{
if (! $this->isModuleActive()) {
return;
}
$this->getCustomerLoginSentry()->abortLoginIfNotActive(
$event->getData('customer')
);
}
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
And this class is
simpler to test?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Yes, as there is
much less logic.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Most of the logic is delegated to
collaborators.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
$this->getCustomerLoginSentry()->abortLoginIfNotActive(
$event->getData('customer')
);
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
How does the
delegation look in
detail?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
private static $sentryClass = 'customeractivation/customerLoginSentry';
/**
* @return Netzarbeiter_CustomerActivation_Model_CustomerLoginSentry
*/
private function getCustomerLoginSentry()
{
return $this->loginSentry ?? Mage::getModel(self::$sentryClass);
}
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
The login sentry can be injected.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
That means,
it can be replaced by a test double.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Dependency
Injection
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
DI is a Magento 2
thing, right?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
DI can be everywhere!
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Injecting Test Doubles
in Magento 1
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Setter Injection
public function testDelegatesToLoginSentry()
{
$mockLoginSentry = $this->createMock(LoginSentry::class);
$mockLoginSentry->expects($this->once())
->method('abortLoginIfNotActive');
$observer = new Netzarbeiter_CustomerActivation_Model_Observer();
$observer->loginSentry = $mockLoginSentry;
// ...
}
Problematic because it makes the class interface less clean.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Constructor Injection
public function testDelegatesToLoginSentry()
{
$mockLoginSentry = $this->createMock(LoginSentry::class);
$mockLoginSentry->expects($this->once())
->method('abortLoginIfNotActive');
$observer = new Netzarbeiter_CustomerActivation_Model_Observer(
$mockLoginSentry
);
// ...
}
Problematic because standard Magento 1 instantiation.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Ugly but works fine.
/**
* @param LoginSentry $loginSentry
*/
public function __construct($loginSentry = null)
{
$this->loginSentry = $loginSentry;
}
// ...
private function getCustomerLoginSentry()
{
return isset($this->loginSentry) ?? Mage::getModel(self::$sentry);
}
Optional Dependencies?! (WTF LOL)
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Injected collaborators
make for simple tests!
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Delegation allow us to create
classes with a specific purpose.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
We can give descriptive names.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Model with specific responsibility
class Netzarbeiter_CustomerActivation_Model_CustomerLoginSentry
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
public function abortLoginIfNotActive(
Mage_Customer_Model_Customer $customer
) {
if (! $customer->getData('customer_activated') {
$this->getSession()->logout();
$this->getDisplay()->showLoginAbortedMessage();
}
}
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
This business logic is now
independent of the entry point
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
It can be called from anywhere
→ Observer
→ Controller
→ Model Rewrite
→ Test
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Back to the example code...
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
There is one other thing here that makes testing easier:
public function customerLogin(Event $event)
{
if (! $this->isModuleActive()) {
return;
}
$this->getCustomerLoginSentry()->abortLoginIfNotActive(
$event->getData('customer')
);
}
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
No magic method call.
// Old code:
$event->getCustomer();
// New code:
$event->getData('customer')
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Why does that
improve testability?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Creating a mock with
magic methods is ugly!
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Noisy code in test is distracting.
$methods = array_merge(
get_class_methods(Event::class),
['getCustomer']
);
$mockEvent = $this->getMockBuilder(Event::class)
->setMethods($methods)
->getMock();
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Much simpler:
$mockEvent = $this->createMock(Event::class);
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Summary
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
What makes code
simple to test?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
→ Separation of
Business Logic
and
Entry Points
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
→ Small classes
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
→ Encapsulation of Business Logic in
specific classes
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
→ Delegation to
injectable dependencies
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
→ Real methods
over
magic methods
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Is there more?
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
→ Law of Demeter.
→ Separation of code that causes side
effects from code that return a value.
→ No method call chaining.
→ Single level of detail within methods.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
Lets keep these for another time.
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
But most importantly...
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
...have fun writing
tests!
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
(tell you me comment)
(ask? you me question)
(thank you)
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
http://mage2katas.com/
Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp

More Related Content

PDF
Getting your Hands Dirty Testing Magento 2 (at London Meetup)
PPTX
Ten quick tips for building muscle!
PPTX
PDF
SFScon16 - Gianluca Antonacci: "The CLEAN-ROADS project case study"
PDF
Marketing Beyond the Website Best Practices to Build Credibility Through Mult...
PDF
Magento 2 + composer
PDF
DOCX
Srikanth Yanamala Dev
Getting your Hands Dirty Testing Magento 2 (at London Meetup)
Ten quick tips for building muscle!
SFScon16 - Gianluca Antonacci: "The CLEAN-ROADS project case study"
Marketing Beyond the Website Best Practices to Build Credibility Through Mult...
Magento 2 + composer
Srikanth Yanamala Dev

Viewers also liked (10)

PDF
Choosing a Citrix Monitoring Strategy: Key Capabilities and Pitfalls to Avoid
PDF
Investor day
PPTX
Magento Presentation Layer
PDF
Spring Cloud Netflix OSS
PPTX
OpenStack 5th Birthday - User Group Parties
PDF
SFScon16 - Francesco Melchiori: "Alyvix"
PDF
Immutable Deployments with AWS CloudFormation and AWS Lambda
PDF
Omnichannel Customer Experience
PDF
CIECH - Wyniki finansowe za 2015 r.
PDF
Highly concurrent yet natural programming
Choosing a Citrix Monitoring Strategy: Key Capabilities and Pitfalls to Avoid
Investor day
Magento Presentation Layer
Spring Cloud Netflix OSS
OpenStack 5th Birthday - User Group Parties
SFScon16 - Francesco Melchiori: "Alyvix"
Immutable Deployments with AWS CloudFormation and AWS Lambda
Omnichannel Customer Experience
CIECH - Wyniki finansowe za 2015 r.
Highly concurrent yet natural programming
Ad

Similar to Writing Testable Code (for Magento 1 and 2) (20)

PDF
Writing Testable Code (for Magento 1 and 2) 2016 Romaina
PDF
Getting your hands dirty testing Magento 2 (at MageTitansIT)
PDF
Writing testable Code (MageTitans Mini 2016)
PDF
Becoming Certified - MageTitansMCR 2018
PPTX
Awesome Architectures in Magento 2.3 - MM19PL
PDF
The productive developer guide to Angular 2
PDF
Magento 2 TDD Code Kata
PDF
Magento 2 TDD Code Kata Intro
PDF
ClojureScript in Magento 2 - PHPUGMRN
PDF
Testing Magento 2
PDF
Architecture in-the-small-slides
PDF
Vinai Kopp - How i develop M2 modules
PDF
How to create a Vue Storefront theme
PDF
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
PPTX
Extension Submission to Marketplace
PDF
Vinai Kopp - FPC Hole punching in Magento 2
PPTX
GraphQL in Magento 2
PDF
Aspnet Mvc 2 In Action 1st Edition Jeffery Palermo Ben Scheirman
PDF
Angular 1.x reloaded: improve your app now! and get ready for 2.0
PDF
A true story about Magento best practices
Writing Testable Code (for Magento 1 and 2) 2016 Romaina
Getting your hands dirty testing Magento 2 (at MageTitansIT)
Writing testable Code (MageTitans Mini 2016)
Becoming Certified - MageTitansMCR 2018
Awesome Architectures in Magento 2.3 - MM19PL
The productive developer guide to Angular 2
Magento 2 TDD Code Kata
Magento 2 TDD Code Kata Intro
ClojureScript in Magento 2 - PHPUGMRN
Testing Magento 2
Architecture in-the-small-slides
Vinai Kopp - How i develop M2 modules
How to create a Vue Storefront theme
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
Extension Submission to Marketplace
Vinai Kopp - FPC Hole punching in Magento 2
GraphQL in Magento 2
Aspnet Mvc 2 In Action 1st Edition Jeffery Palermo Ben Scheirman
Angular 1.x reloaded: improve your app now! and get ready for 2.0
A true story about Magento best practices
Ad

More from vinaikopp (11)

PPTX
Building Mage-OS - MageTitans 2023
PDF
Hyvä: Compatibility Modules
PDF
Hyvä from a developer perspective
PDF
Property Based Testing in PHP
PDF
Property based testing - MageTestFest 2019
PDF
SOS UiComponents
PDF
ClojureScript in Magento 2 - MageTitansMCR 2017
PDF
Lizards & Pumpkins Catalog Replacement at mm17de
PDF
Stories from the other side
PPT
Modern Module Architecture
PPT
The beautiful Magento module - MageTitans 2014
Building Mage-OS - MageTitans 2023
Hyvä: Compatibility Modules
Hyvä from a developer perspective
Property Based Testing in PHP
Property based testing - MageTestFest 2019
SOS UiComponents
ClojureScript in Magento 2 - MageTitansMCR 2017
Lizards & Pumpkins Catalog Replacement at mm17de
Stories from the other side
Modern Module Architecture
The beautiful Magento module - MageTitans 2014

Recently uploaded (20)

PPTX
ai tools demonstartion for schools and inter college
PDF
Digital Strategies for Manufacturing Companies
PDF
System and Network Administration Chapter 2
PDF
Nekopoi APK 2025 free lastest update
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PPTX
Introduction to Artificial Intelligence
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PPTX
Computer Software and OS of computer science of grade 11.pptx
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PPT
Introduction Database Management System for Course Database
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
medical staffing services at VALiNTRY
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PPTX
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
PPTX
history of c programming in notes for students .pptx
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
ai tools demonstartion for schools and inter college
Digital Strategies for Manufacturing Companies
System and Network Administration Chapter 2
Nekopoi APK 2025 free lastest update
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Introduction to Artificial Intelligence
Design an Analysis of Algorithms II-SECS-1021-03
Odoo Companies in India – Driving Business Transformation.pdf
Computer Software and OS of computer science of grade 11.pptx
How to Migrate SBCGlobal Email to Yahoo Easily
Introduction Database Management System for Course Database
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
medical staffing services at VALiNTRY
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
How to Choose the Right IT Partner for Your Business in Malaysia
Design an Analysis of Algorithms I-SECS-1021-03
Internet Downloader Manager (IDM) Crack 6.42 Build 41
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
history of c programming in notes for students .pptx
Adobe Illustrator 28.6 Crack My Vision of Vector Design

Writing Testable Code (for Magento 1 and 2)

  • 1. Writing Testable Code (for Magento 1 and 2) Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 2. Assumptions Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 3. You know basic PHPUnit. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 4. You want → Confidence in deploys → Experience joy when writing tests → Have fun doing code maintaince → Get more $$$ from testing Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 5. In short, you want → Testable code Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 6. When is code "testable"? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 7. When testing is simple & easy. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 8. What makes a test simple? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 9. It is simple to write. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 10. It is easy to read. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 11. What does "easy to read" mean? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 12. It's intent is clear. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 13. The test is short. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 14. Good names. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 15. It only does one thing. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 16. Clean Code is for Production Code & Test Code Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 17. What does "simple to write" mean? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 18. Test code depends on production code Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 19. It are properties of the production code that make testing easy or hard. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 20. "It's no big thing, but you make big things out of little things sometimes." ~~ Robert Duvall Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 21. What does easy to test code look like? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 22. A bad case of legacy: Event Observer (for Magento 1) Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 23. <?php use Varien_Event_Observer as Event; class Netzarbeiter_CustomerActivation_Model_Observer { // Check if the customer has been activated, if not, throw login error public function customerLogin(Event $event) {...} // Flag new accounts as such public function customerSaveBefore(Event $event) {...} // Send out emails public function customerSaveAfter(Event $event) {...} // Abort registration during checkout if default activation status is false public function salesConvertQuoteAddressToOrder(Event $event) {...} // Add customer activation option to the mass action block public function adminhtmlBlockHtmlBefore(Event $event) {...} // Add the customer_activated attribute to the customer grid collection public function eavCollectionAbstractLoadBefore(Event $event) {...} // Add customer_activated column to CSV and XML exports public function coreBlockAbstractPrepareLayoutAfter(Event $event) {...} // Remove the customer id from the customer/session, in effect causing a logout public function actionPostdispatchCustomerAccountResetPasswordPost(Event $event) {...} } Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 24. Are we going to write Unit Tests? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 25. For > 500 lines of legacy? Hell NO! Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 26. What would make it simpler to test? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 27. If the class where smallerit would be simpler to test. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 28. First attempt: Splitting the class based on purpose. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 29. What does the class do? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 30. 1. Prevents inactive customer logins. 2. Sends notification emails. 3. Adds a column to the customer grid. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 31. Lets split it into Netzarbeiter_CustomerActivation_Model... ..._Observer_ProhibitInactiveLogins ..._Observer_EmailNotifications ..._Observer_AdminhtmlCustomerGrid Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 32. <?php use Varien_Event_Observer as Event; class Netzarbeiter_CustomerActivation_Model_Observer_ProhibitInactiveLogin { // Check if the customer has been activated, if not, throw login error public function customerLogin(Event $event) {...} // Abort registration during checkout if default activation status is false public function salesConvertQuoteAddressToOrder(Event $event) {...} // Remove the customer ID from the customer/session causing a logout public function actionPostdispatchCustomerAccountResetPasswordPost(Event $event) {...} } Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 33. <?php use Varien_Event_Observer as Event; class Netzarbeiter_CustomerActivation_Model_Observer_EmailNotifications { // Flag new accounts as such public function customerSaveBefore(Event $event) {...} // Send out emails public function customerSaveAfter(Event $event) {...} } Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 34. <?php use Varien_Event_Observer as Event; class Netzarbeiter_CustomerActivation_Model_Observer_AdminhtmlCustomerGrid { // Add customer activation option to the mass action block public function adminhtmlBlockHtmlBefore(Event $event) {...} // Add the customer_activated attribute to the customer grid collection public function eavCollectionAbstractLoadBefore(Event $event) {...} // Add customer_activated column to CSV and XML exports public function coreBlockAbstractPrepareLayoutAfter(Event $event) {...} } Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 35. Is this simpler to test? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 36. Only minor difference in testing effort. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 37. Why? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 38. The same tests as before. Only split into three classes. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 39. Second attempt: Lets go beyond superficial changes. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 40. Lets look at the design. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 41. What collaborators are used? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 43. Almost all of them are core classes. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 44. Only two classes are part of the module: Netzarbeiter_CustomerActivation_Model_Observer Netzarbeiter_CustomerActivation_Helper_Data Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 45. Based on the names, why do they exist? Netzarbeiter_CustomerActivation_Model_Observer Netzarbeiter_CustomerActivation_Helper_Data Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 46. The names don't tell us anything. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 47. Extract parts by giving them meaningful names Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 48. But where to start? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 49. Separate business logic from the entry points. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 50. Entry points are the places Magento provides us to put our custom code. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 51. Entry points: → Observers → Plugins → Controllers → Cron Jobs → Preferences → Console Commands Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 52. Entry points link Business logic ! Magento Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 53. Remove all Business Logic from Entry Points. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 54. What are the benefits? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 55. For testing: The custom code can be triggered independently of the entry point. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 56. In or example, what is the entry point? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 57. Observer Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 58. Old Observer Code: Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 59. public function customerLogin($observer) { $helper = Mage::helper('customeractivation'); if (!$helper->isModuleActive()) { return; } if ($this->_isApiRequest()) { return; } $customer = $observer->getEvent()->getCustomer(); $session = Mage::getSingleton('customer/session'); if (!$customer->getCustomerActivated()) { $session->setCustomer(Mage::getModel('customer/customer')) ->setId(null) ->setCustomerGroupId(Mage_Customer_Model_Group::NOT_LOGGED_IN_ID); if ($this->_checkRequestRoute('customer', 'account', 'createpost')) { $message = $helper->__('Please wait for your account to be activated'); $session->addSuccess($message); } else { Mage::throwException($helper->__('This account is not activated.')); } } } Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 60. New Code, without business logic: Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 61. public function customerLogin(Event $event) { if (! $this->isModuleActive()) { return; } $this->getCustomerLoginSentry()->abortLoginIfNotActive( $event->getData('customer') ); } Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 62. And this class is simpler to test? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 63. Yes, as there is much less logic. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 64. Most of the logic is delegated to collaborators. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 66. How does the delegation look in detail? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 67. private static $sentryClass = 'customeractivation/customerLoginSentry'; /** * @return Netzarbeiter_CustomerActivation_Model_CustomerLoginSentry */ private function getCustomerLoginSentry() { return $this->loginSentry ?? Mage::getModel(self::$sentryClass); } Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 68. The login sentry can be injected. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 69. That means, it can be replaced by a test double. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 70. Dependency Injection Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 71. DI is a Magento 2 thing, right? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 72. DI can be everywhere! Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 73. Injecting Test Doubles in Magento 1 Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 74. Setter Injection public function testDelegatesToLoginSentry() { $mockLoginSentry = $this->createMock(LoginSentry::class); $mockLoginSentry->expects($this->once()) ->method('abortLoginIfNotActive'); $observer = new Netzarbeiter_CustomerActivation_Model_Observer(); $observer->loginSentry = $mockLoginSentry; // ... } Problematic because it makes the class interface less clean. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 75. Constructor Injection public function testDelegatesToLoginSentry() { $mockLoginSentry = $this->createMock(LoginSentry::class); $mockLoginSentry->expects($this->once()) ->method('abortLoginIfNotActive'); $observer = new Netzarbeiter_CustomerActivation_Model_Observer( $mockLoginSentry ); // ... } Problematic because standard Magento 1 instantiation. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 76. Ugly but works fine. /** * @param LoginSentry $loginSentry */ public function __construct($loginSentry = null) { $this->loginSentry = $loginSentry; } // ... private function getCustomerLoginSentry() { return isset($this->loginSentry) ?? Mage::getModel(self::$sentry); } Optional Dependencies?! (WTF LOL) Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 77. Injected collaborators make for simple tests! Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 78. Delegation allow us to create classes with a specific purpose. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 79. We can give descriptive names. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 80. Model with specific responsibility class Netzarbeiter_CustomerActivation_Model_CustomerLoginSentry Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 81. public function abortLoginIfNotActive( Mage_Customer_Model_Customer $customer ) { if (! $customer->getData('customer_activated') { $this->getSession()->logout(); $this->getDisplay()->showLoginAbortedMessage(); } } Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 82. This business logic is now independent of the entry point Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 83. It can be called from anywhere → Observer → Controller → Model Rewrite → Test Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 84. Back to the example code... Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 85. There is one other thing here that makes testing easier: public function customerLogin(Event $event) { if (! $this->isModuleActive()) { return; } $this->getCustomerLoginSentry()->abortLoginIfNotActive( $event->getData('customer') ); } Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 86. No magic method call. // Old code: $event->getCustomer(); // New code: $event->getData('customer') Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 87. Why does that improve testability? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 88. Creating a mock with magic methods is ugly! Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 89. Noisy code in test is distracting. $methods = array_merge( get_class_methods(Event::class), ['getCustomer'] ); $mockEvent = $this->getMockBuilder(Event::class) ->setMethods($methods) ->getMock(); Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 90. Much simpler: $mockEvent = $this->createMock(Event::class); Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 91. Summary Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 92. What makes code simple to test? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 93. → Separation of Business Logic and Entry Points Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 94. → Small classes Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 95. → Encapsulation of Business Logic in specific classes Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 96. → Delegation to injectable dependencies Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 97. → Real methods over magic methods Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 98. Is there more? Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 99. → Law of Demeter. → Separation of code that causes side effects from code that return a value. → No method call chaining. → Single level of detail within methods. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 100. Lets keep these for another time. Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 101. But most importantly... Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 102. ...have fun writing tests! Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 103. (tell you me comment) (ask? you me question) (thank you) Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp
  • 104. http://mage2katas.com/ Writing Testable Code in Magento 1 and 2 - #MM16PL 2016-09-19 - twitter://@VinaiKopp