SlideShare a Scribd company logo
Writing Testable Code
(for Magento 1 and 2)
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Assumptions!
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
You know basic PHPUnit.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
You want
→ Confidence in deploys
→ Experience joy when writing tests
→ Have fun doing code maintaince
→ Get more $$$ out of testing
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
In short, you want
→ Testable code
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
When is code "testable"?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
When testing
is simple & easy.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
What makes a
test simple?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
It is simple to write.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
It is easy to read.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
What does
"easy to read"
mean?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
It's intent is clear.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
The test is short.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Good names.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
It only does
one thing.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Clean Code
is for
Production Code
& Test Code
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
What does
"simple to write"
mean?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Test code
depends on
production code
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
It are properties of the
production code
that make testing
easy or hard.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
What does easy to test
code look like?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Magento 1 Example:
Event Observer
(Legacy Code)
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Are we going to write
Unit Tests?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Hell NO!
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Unit tests only provide
value for new code.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
For previously untested code,
Integration Tests
are much more valuable.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
What would make it
simpler to test?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
If the class where
smallerit would be simpler to test.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
First attempt:
Splitting the class based on purpose.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
What does the
class do?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Lets split it into
Netzarbeiter_CustomerActivation_Model...
..._Observer_ProhibitInactiveLogins
..._Observer_EmailNotifications
..._Observer_AdminhtmlCustomerGrid
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - 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 - #MM16RO 2016-10-28 - 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 - #MM16RO 2016-10-28 - 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Is this simpler
to test?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Only minor difference in
testing effort.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Why?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
The same tests as before.
Only split into three classes.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Second attempt:
Lets go beyond
superficial changes.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Lets look at the design.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
What collaborators are used?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Almost all of them are core classes.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Based on the names,
why do these classes exist?
Netzarbeiter_CustomerActivation_Model_Observer
Netzarbeiter_CustomerActivation_Helper_Data
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
The names don't
tell us anything.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Extract parts by giving them
meaningful names
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
But where to start?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Separate business logic
from entry points.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Entry points are the places Magento provides for
our custom code.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Entry points:
→ Observers
→ Plugins
→ Controllers
→ Cron Jobs
→ Preferences
→ Console Commands
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Entry points link
Business logic
!
Magento
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Remove all
Business Logic
from
Entry Points.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
What are the benefits?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
For testing:
The custom code can be triggered
independently of the entry point.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
In our example,
what is the
entry point?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Observer
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Old Observer Code:
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
New Code, without business logic:
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
And this class is
simpler to test?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Yes, as there is
much less logic.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Most of the logic is delegated to collaborators.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
$this->getCustomerLoginSentry()->abortLoginIfNotActive(
$event->getData('customer')
);
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
How does the delegation
look in detail?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
private static $sentryClass = 'customeractivation/customerLoginSentry';
/**
* @return CustomerLoginSentry
*/
private function getCustomerLoginSentry()
{
return $this->loginSentry ?? Mage::getModel(self::$sentryClass);
}
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
The login sentry can be injected.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
That means,
it can be replaced by a test double.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Dependency Injection
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
DI is a Magento 2 thing,
right?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
DI can be everywhere!
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Injecting Test Doubles
in Magento 1
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - 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;
// ...
}
Problem: It muddies intention revealing class interfaces.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - 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
);
// ...
}
Problem: Standard Magento 1 instantiation can't do it.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Ugly but hey it works.
/**
* @param LoginSentry $loginSentry
*/
public function __construct($loginSentry = null)
{
$this->loginSentry = $loginSentry;
}
// ...
private function getCustomerLoginSentry()
{
return $this->loginSentry ?? Mage::getModel(self::$sentry);
}
Paradoxical: Optional Dependency Injection..? o_O
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Injected collaborators
make for simple tests!
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Delegation allow us to create
classes with a specific purpose.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
We can give descriptive names.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Model with one responsibility:
class Netzarbeiter_CustomerActivation_Model_CustomerLoginSentry
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
This business logic is now
independent of the entry point.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
It can be called from anywhere:
→ Test
→ Observer
→ Controller
→ Model Rewrite
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Back to the example code...
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
One other subtle thing here 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
No magic method __call() calls!
// Old "magic" code:
$event->getCustomer();
// New code:
$event->getData('customer')
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Why does that
improve testability?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Creating a mock with
magic methods is ugly!
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Lots of setup code in tests
distracts
from the important parts.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Noisy test double creation:
$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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Much nicer:
$mockEvent = $this->createMock(Event::class);
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Summary
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
What makes code
simple to test?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
→ Separation of
Business Logic
from
Entry Points
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
→ Small classes
(and methods)
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
→ Encapsulation of
Business Logic in
specific classes
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
→ Delegation to
injectable dependencies
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
→ Favoring
real methods
over
magic methods
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Is there more?
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Yes!
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
→ Adherence to the Law of Demeter.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
→ Separation of methods that causes
side effects from
methods returning values.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
→ Avoidance of method call chaining.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
→ Methods having a single level of detail.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
Lets keep these for another time.
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
So most importantly...
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
...have fun writing tests!
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
(tell you me comment)
(ask? you me question)
(thank you)
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
http://mage2katas.com/
Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp

More Related Content

PDF
Testing Magento 2
PDF
Magento 2 TDD Code Kata Intro
PDF
Getting your hands dirty testing Magento 2 (at MageTitansIT)
PDF
Magento 2 TDD Code Kata
PDF
Becoming Certified - MageTitansMCR 2018
PDF
Magento Security Best Practises - MM17DE
PDF
ClojureScript in Magento 2 - PHPUGMRN
PDF
Hyvä: Compatibility Modules
Testing Magento 2
Magento 2 TDD Code Kata Intro
Getting your hands dirty testing Magento 2 (at MageTitansIT)
Magento 2 TDD Code Kata
Becoming Certified - MageTitansMCR 2018
Magento Security Best Practises - MM17DE
ClojureScript in Magento 2 - PHPUGMRN
Hyvä: Compatibility Modules

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

PDF
Writing Testable Code (for Magento 1 and 2)
PDF
Writing testable Code (MageTitans Mini 2016)
PPTX
Testing in Magento 2
PDF
Vinai Kopp - How i develop M2 modules
PPTX
Automated Testing in Magento 2
PPTX
Magento 2 Automated Testing via examples of Multi-Source Inventory (MSI)
PPTX
Igor Miniailo - Magento 2 API Design Best Practices
PPTX
Dusan Lukic Magento 2 Integration Tests Meet Magento Serbia 2016
PPTX
Growing up with Magento
PPT
Meet Magento DE 2016 - Kristof Ringleff - Growing up with Magento
PDF
The journey of mastering Magento 2 for Magento 1 developers
PPTX
Code Quality with Magento 2
PDF
A Successful Magento Project From Design to Deployment
PPTX
Applying Code Customizations to Magento 2
PPT
Meet Magento Belarus - Elena Leonova
PDF
Magento 2 integration tests
PDF
Getting your Hands Dirty Testing Magento 2 (at London Meetup)
PPTX
Magento2.3 API Functional Testing
PPTX
Using of TDD practices for Magento
PPT
Meet Magento Belarus - Magento2: What to expect and when? - Elena Leonova
Writing Testable Code (for Magento 1 and 2)
Writing testable Code (MageTitans Mini 2016)
Testing in Magento 2
Vinai Kopp - How i develop M2 modules
Automated Testing in Magento 2
Magento 2 Automated Testing via examples of Multi-Source Inventory (MSI)
Igor Miniailo - Magento 2 API Design Best Practices
Dusan Lukic Magento 2 Integration Tests Meet Magento Serbia 2016
Growing up with Magento
Meet Magento DE 2016 - Kristof Ringleff - Growing up with Magento
The journey of mastering Magento 2 for Magento 1 developers
Code Quality with Magento 2
A Successful Magento Project From Design to Deployment
Applying Code Customizations to Magento 2
Meet Magento Belarus - Elena Leonova
Magento 2 integration tests
Getting your Hands Dirty Testing Magento 2 (at London Meetup)
Magento2.3 API Functional Testing
Using of TDD practices for Magento
Meet Magento Belarus - Magento2: What to expect and when? - Elena Leonova
Ad

More from vinaikopp (11)

PPTX
Building Mage-OS - MageTitans 2023
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
PDF
Architecture in-the-small-slides
PPT
Modern Module Architecture
PPT
The beautiful Magento module - MageTitans 2014
Building Mage-OS - MageTitans 2023
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
Architecture in-the-small-slides
Modern Module Architecture
The beautiful Magento module - MageTitans 2014
Ad

Recently uploaded (20)

PPTX
L1 - Introduction to python Backend.pptx
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
System and Network Administraation Chapter 3
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
top salesforce developer skills in 2025.pdf
PPTX
Transform Your Business with a Software ERP System
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PPTX
Computer Software and OS of computer science of grade 11.pptx
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
L1 - Introduction to python Backend.pptx
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Odoo Companies in India – Driving Business Transformation.pdf
System and Network Administraation Chapter 3
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Operating system designcfffgfgggggggvggggggggg
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Softaken Excel to vCard Converter Software.pdf
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
top salesforce developer skills in 2025.pdf
Transform Your Business with a Software ERP System
CHAPTER 2 - PM Management and IT Context
Navsoft: AI-Powered Business Solutions & Custom Software Development
VVF-Customer-Presentation2025-Ver1.9.pptx
Computer Software and OS of computer science of grade 11.pptx
Which alternative to Crystal Reports is best for small or large businesses.pdf
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises

Writing Testable Code (for Magento 1 and 2) 2016 Romaina

  • 1. Writing Testable Code (for Magento 1 and 2) Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 2. Assumptions! Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 3. You know basic PHPUnit. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 4. You want → Confidence in deploys → Experience joy when writing tests → Have fun doing code maintaince → Get more $$$ out of testing Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 5. In short, you want → Testable code Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 6. When is code "testable"? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 7. When testing is simple & easy. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 8. What makes a test simple? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 9. It is simple to write. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 10. It is easy to read. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 11. What does "easy to read" mean? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 12. It's intent is clear. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 13. The test is short. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 14. Good names. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 15. It only does one thing. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 16. Clean Code is for Production Code & Test Code Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 17. What does "simple to write" mean? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 18. Test code depends on production code Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 19. It are properties of the production code that make testing easy or hard. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 20. What does easy to test code look like? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 21. Magento 1 Example: Event Observer (Legacy Code) Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 22. <?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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 23. Are we going to write Unit Tests? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 24. Hell NO! Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 25. Unit tests only provide value for new code. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 26. For previously untested code, Integration Tests are much more valuable. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 27. What would make it simpler to test? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 28. If the class where smallerit would be simpler to test. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 29. First attempt: Splitting the class based on purpose. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 30. What does the class do? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 31. 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 32. Lets split it into Netzarbeiter_CustomerActivation_Model... ..._Observer_ProhibitInactiveLogins ..._Observer_EmailNotifications ..._Observer_AdminhtmlCustomerGrid Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 33. <?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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 34. <?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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 35. <?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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 36. Is this simpler to test? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 37. Only minor difference in testing effort. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 38. Why? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 39. The same tests as before. Only split into three classes. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 40. Second attempt: Lets go beyond superficial changes. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 41. Lets look at the design. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 42. What collaborators are used? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 44. Almost all of them are core classes. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 45. Only two classes are part of the module: Netzarbeiter_CustomerActivation_Model_Observer Netzarbeiter_CustomerActivation_Helper_Data Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 46. Based on the names, why do these classes exist? Netzarbeiter_CustomerActivation_Model_Observer Netzarbeiter_CustomerActivation_Helper_Data Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 47. The names don't tell us anything. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 48. Extract parts by giving them meaningful names Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 49. But where to start? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 50. Separate business logic from entry points. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 51. Entry points are the places Magento provides for our custom code. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 52. Entry points: → Observers → Plugins → Controllers → Cron Jobs → Preferences → Console Commands Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 53. Entry points link Business logic ! Magento Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 54. Remove all Business Logic from Entry Points. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 55. What are the benefits? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 56. For testing: The custom code can be triggered independently of the entry point. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 57. In our example, what is the entry point? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 58. Observer Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 59. Old Observer Code: Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 60. 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 61. New Code, without business logic: Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 62. public function customerLogin(Event $event) { if (! $this->isModuleActive()) { return; } $this->getCustomerLoginSentry()->abortLoginIfNotActive( $event->getData('customer') ); } Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 63. And this class is simpler to test? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 64. Yes, as there is much less logic. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 65. Most of the logic is delegated to collaborators. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 67. How does the delegation look in detail? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 68. private static $sentryClass = 'customeractivation/customerLoginSentry'; /** * @return CustomerLoginSentry */ private function getCustomerLoginSentry() { return $this->loginSentry ?? Mage::getModel(self::$sentryClass); } Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 69. The login sentry can be injected. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 70. That means, it can be replaced by a test double. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 71. Dependency Injection Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 72. DI is a Magento 2 thing, right? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 73. DI can be everywhere! Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 74. Injecting Test Doubles in Magento 1 Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 75. 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; // ... } Problem: It muddies intention revealing class interfaces. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 76. Constructor Injection public function testDelegatesToLoginSentry() { $mockLoginSentry = $this->createMock(LoginSentry::class); $mockLoginSentry->expects($this->once()) ->method('abortLoginIfNotActive'); $observer = new Netzarbeiter_CustomerActivation_Model_Observer( $mockLoginSentry ); // ... } Problem: Standard Magento 1 instantiation can't do it. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 77. Ugly but hey it works. /** * @param LoginSentry $loginSentry */ public function __construct($loginSentry = null) { $this->loginSentry = $loginSentry; } // ... private function getCustomerLoginSentry() { return $this->loginSentry ?? Mage::getModel(self::$sentry); } Paradoxical: Optional Dependency Injection..? o_O Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 78. Injected collaborators make for simple tests! Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 79. Delegation allow us to create classes with a specific purpose. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 80. We can give descriptive names. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 81. Model with one responsibility: class Netzarbeiter_CustomerActivation_Model_CustomerLoginSentry Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 82. 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 83. This business logic is now independent of the entry point. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 84. It can be called from anywhere: → Test → Observer → Controller → Model Rewrite Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 85. Back to the example code... Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 86. One other subtle thing here 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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 87. No magic method __call() calls! // Old "magic" code: $event->getCustomer(); // New code: $event->getData('customer') Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 88. Why does that improve testability? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 89. Creating a mock with magic methods is ugly! Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 90. Lots of setup code in tests distracts from the important parts. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 91. Noisy test double creation: $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 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 92. Much nicer: $mockEvent = $this->createMock(Event::class); Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 93. Summary Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 94. What makes code simple to test? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 95. → Separation of Business Logic from Entry Points Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 96. → Small classes (and methods) Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 97. → Encapsulation of Business Logic in specific classes Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 98. → Delegation to injectable dependencies Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 99. → Favoring real methods over magic methods Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 100. Is there more? Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 101. Yes! Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 102. → Adherence to the Law of Demeter. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 103. → Separation of methods that causes side effects from methods returning values. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 104. → Avoidance of method call chaining. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 105. → Methods having a single level of detail. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 106. Lets keep these for another time. Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 107. So most importantly... Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 108. ...have fun writing tests! Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 109. (tell you me comment) (ask? you me question) (thank you) Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp
  • 110. http://mage2katas.com/ Writing Testable Code in Magento 1 and 2 - #MM16RO 2016-10-28 - twitter://@VinaiKopp