SlideShare ist ein Scribd-Unternehmen logo
1 von 104
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Andere mochten auch

Choosing a Citrix Monitoring Strategy: Key Capabilities and Pitfalls to Avoid
Choosing a Citrix Monitoring Strategy: Key Capabilities and Pitfalls to AvoidChoosing a Citrix Monitoring Strategy: Key Capabilities and Pitfalls to Avoid
Choosing a Citrix Monitoring Strategy: Key Capabilities and Pitfalls to AvoideG Innovations
 
Spring Cloud Netflix OSS
Spring Cloud Netflix OSSSpring Cloud Netflix OSS
Spring Cloud Netflix OSSSteve Hall
 
OpenStack 5th Birthday - User Group Parties
OpenStack 5th Birthday - User Group PartiesOpenStack 5th Birthday - User Group Parties
OpenStack 5th Birthday - User Group PartiesOpenStack Foundation
 
Immutable Deployments with AWS CloudFormation and AWS Lambda
Immutable Deployments with AWS CloudFormation and AWS LambdaImmutable Deployments with AWS CloudFormation and AWS Lambda
Immutable Deployments with AWS CloudFormation and AWS LambdaAOE
 
Omnichannel Customer Experience
Omnichannel Customer ExperienceOmnichannel Customer Experience
Omnichannel Customer ExperienceDivante
 
CIECH - Wyniki finansowe za 2015 r.
CIECH - Wyniki finansowe za 2015 r.CIECH - Wyniki finansowe za 2015 r.
CIECH - Wyniki finansowe za 2015 r.CIECH Group IR
 
Highly concurrent yet natural programming
Highly concurrent yet natural programmingHighly concurrent yet natural programming
Highly concurrent yet natural programmingInfinit
 

Andere mochten auch (10)

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

Ähnlich wie Writing Testable Code (for Magento 1 and 2)

Writing Testable Code (for Magento 1 and 2) 2016 Romaina
Writing Testable Code (for Magento 1 and 2)  2016 RomainaWriting Testable Code (for Magento 1 and 2)  2016 Romaina
Writing Testable Code (for Magento 1 and 2) 2016 Romainavinaikopp
 
Getting your hands dirty testing Magento 2 (at MageTitansIT)
Getting your hands dirty testing Magento 2 (at MageTitansIT)Getting your hands dirty testing Magento 2 (at MageTitansIT)
Getting your hands dirty testing Magento 2 (at MageTitansIT)vinaikopp
 
Writing testable Code (MageTitans Mini 2016)
Writing testable Code (MageTitans Mini 2016)Writing testable Code (MageTitans Mini 2016)
Writing testable Code (MageTitans Mini 2016)vinaikopp
 
Becoming Certified - MageTitansMCR 2018
Becoming Certified - MageTitansMCR 2018Becoming Certified - MageTitansMCR 2018
Becoming Certified - MageTitansMCR 2018vinaikopp
 
Awesome Architectures in Magento 2.3 - MM19PL
Awesome Architectures in Magento 2.3 - MM19PLAwesome Architectures in Magento 2.3 - MM19PL
Awesome Architectures in Magento 2.3 - MM19PLRiccardo Tempesta
 
The productive developer guide to Angular 2
The productive developer guide to Angular 2The productive developer guide to Angular 2
The productive developer guide to Angular 2Maurice De Beijer [MVP]
 
Magento 2 TDD Code Kata
Magento 2 TDD Code KataMagento 2 TDD Code Kata
Magento 2 TDD Code Katavinaikopp
 
Magento 2 TDD Code Kata Intro
Magento 2 TDD Code Kata IntroMagento 2 TDD Code Kata Intro
Magento 2 TDD Code Kata Introvinaikopp
 
ClojureScript in Magento 2 - PHPUGMRN
ClojureScript in Magento 2 - PHPUGMRNClojureScript in Magento 2 - PHPUGMRN
ClojureScript in Magento 2 - PHPUGMRNvinaikopp
 
Testing Magento 2
Testing Magento 2Testing Magento 2
Testing Magento 2vinaikopp
 
Architecture in-the-small-slides
Architecture in-the-small-slidesArchitecture in-the-small-slides
Architecture in-the-small-slidesvinaikopp
 
Vinai Kopp - How i develop M2 modules
Vinai Kopp - How i develop M2 modules Vinai Kopp - How i develop M2 modules
Vinai Kopp - How i develop M2 modules Meet Magento Italy
 
How to create a Vue Storefront theme
How to create a Vue Storefront themeHow to create a Vue Storefront theme
How to create a Vue Storefront themeDivante
 
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by DefaultJS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by DefaultJSFestUA
 
Extension Submission to Marketplace
Extension Submission to MarketplaceExtension Submission to Marketplace
Extension Submission to MarketplaceWagento Kangiya
 
Vinai Kopp - FPC Hole punching in Magento 2
Vinai Kopp - FPC Hole punching in Magento 2Vinai Kopp - FPC Hole punching in Magento 2
Vinai Kopp - FPC Hole punching in Magento 2Meet Magento Italy
 
Angular 1.x reloaded: improve your app now! and get ready for 2.0
Angular 1.x reloaded:  improve your app now! and get ready for 2.0Angular 1.x reloaded:  improve your app now! and get ready for 2.0
Angular 1.x reloaded: improve your app now! and get ready for 2.0Carlo Bonamico
 
A true story about Magento best practices
A true story about Magento best practicesA true story about Magento best practices
A true story about Magento best practicesAlessandro Ronchi
 
Modern Module Architecture
Modern Module ArchitectureModern Module Architecture
Modern Module Architecturevinaikopp
 

Ähnlich wie Writing Testable Code (for Magento 1 and 2) (20)

Writing Testable Code (for Magento 1 and 2) 2016 Romaina
Writing Testable Code (for Magento 1 and 2)  2016 RomainaWriting Testable Code (for Magento 1 and 2)  2016 Romaina
Writing Testable Code (for Magento 1 and 2) 2016 Romaina
 
Getting your hands dirty testing Magento 2 (at MageTitansIT)
Getting your hands dirty testing Magento 2 (at MageTitansIT)Getting your hands dirty testing Magento 2 (at MageTitansIT)
Getting your hands dirty testing Magento 2 (at MageTitansIT)
 
Writing testable Code (MageTitans Mini 2016)
Writing testable Code (MageTitans Mini 2016)Writing testable Code (MageTitans Mini 2016)
Writing testable Code (MageTitans Mini 2016)
 
Becoming Certified - MageTitansMCR 2018
Becoming Certified - MageTitansMCR 2018Becoming Certified - MageTitansMCR 2018
Becoming Certified - MageTitansMCR 2018
 
Awesome Architectures in Magento 2.3 - MM19PL
Awesome Architectures in Magento 2.3 - MM19PLAwesome Architectures in Magento 2.3 - MM19PL
Awesome Architectures in Magento 2.3 - MM19PL
 
The productive developer guide to Angular 2
The productive developer guide to Angular 2The productive developer guide to Angular 2
The productive developer guide to Angular 2
 
Magento 2 TDD Code Kata
Magento 2 TDD Code KataMagento 2 TDD Code Kata
Magento 2 TDD Code Kata
 
Magento 2 TDD Code Kata Intro
Magento 2 TDD Code Kata IntroMagento 2 TDD Code Kata Intro
Magento 2 TDD Code Kata Intro
 
ClojureScript in Magento 2 - PHPUGMRN
ClojureScript in Magento 2 - PHPUGMRNClojureScript in Magento 2 - PHPUGMRN
ClojureScript in Magento 2 - PHPUGMRN
 
Testing Magento 2
Testing Magento 2Testing Magento 2
Testing Magento 2
 
Architecture in-the-small-slides
Architecture in-the-small-slidesArchitecture in-the-small-slides
Architecture in-the-small-slides
 
Vinai Kopp - How i develop M2 modules
Vinai Kopp - How i develop M2 modules Vinai Kopp - How i develop M2 modules
Vinai Kopp - How i develop M2 modules
 
How to create a Vue Storefront theme
How to create a Vue Storefront themeHow to create a Vue Storefront theme
How to create a Vue Storefront theme
 
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by DefaultJS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
 
Extension Submission to Marketplace
Extension Submission to MarketplaceExtension Submission to Marketplace
Extension Submission to Marketplace
 
Vinai Kopp - FPC Hole punching in Magento 2
Vinai Kopp - FPC Hole punching in Magento 2Vinai Kopp - FPC Hole punching in Magento 2
Vinai Kopp - FPC Hole punching in Magento 2
 
GraphQL in Magento 2
GraphQL in Magento 2GraphQL in Magento 2
GraphQL in Magento 2
 
Angular 1.x reloaded: improve your app now! and get ready for 2.0
Angular 1.x reloaded:  improve your app now! and get ready for 2.0Angular 1.x reloaded:  improve your app now! and get ready for 2.0
Angular 1.x reloaded: improve your app now! and get ready for 2.0
 
A true story about Magento best practices
A true story about Magento best practicesA true story about Magento best practices
A true story about Magento best practices
 
Modern Module Architecture
Modern Module ArchitectureModern Module Architecture
Modern Module Architecture
 

Mehr von vinaikopp

Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023vinaikopp
 
Hyvä: Compatibility Modules
Hyvä: Compatibility ModulesHyvä: Compatibility Modules
Hyvä: Compatibility Modulesvinaikopp
 
Hyvä from a developer perspective
Hyvä from a developer perspectiveHyvä from a developer perspective
Hyvä from a developer perspectivevinaikopp
 
Property Based Testing in PHP
Property Based Testing in PHPProperty Based Testing in PHP
Property Based Testing in PHPvinaikopp
 
Property based testing - MageTestFest 2019
Property based testing - MageTestFest 2019Property based testing - MageTestFest 2019
Property based testing - MageTestFest 2019vinaikopp
 
SOS UiComponents
SOS UiComponentsSOS UiComponents
SOS UiComponentsvinaikopp
 
ClojureScript in Magento 2 - MageTitansMCR 2017
ClojureScript in Magento 2 - MageTitansMCR 2017ClojureScript in Magento 2 - MageTitansMCR 2017
ClojureScript in Magento 2 - MageTitansMCR 2017vinaikopp
 
Lizards & Pumpkins Catalog Replacement at mm17de
Lizards & Pumpkins Catalog Replacement at mm17deLizards & Pumpkins Catalog Replacement at mm17de
Lizards & Pumpkins Catalog Replacement at mm17devinaikopp
 
Stories from the other side
Stories from the other sideStories from the other side
Stories from the other sidevinaikopp
 
The beautiful Magento module - MageTitans 2014
The beautiful Magento module - MageTitans 2014The beautiful Magento module - MageTitans 2014
The beautiful Magento module - MageTitans 2014vinaikopp
 

Mehr von vinaikopp (10)

Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023
 
Hyvä: Compatibility Modules
Hyvä: Compatibility ModulesHyvä: Compatibility Modules
Hyvä: Compatibility Modules
 
Hyvä from a developer perspective
Hyvä from a developer perspectiveHyvä from a developer perspective
Hyvä from a developer perspective
 
Property Based Testing in PHP
Property Based Testing in PHPProperty Based Testing in PHP
Property Based Testing in PHP
 
Property based testing - MageTestFest 2019
Property based testing - MageTestFest 2019Property based testing - MageTestFest 2019
Property based testing - MageTestFest 2019
 
SOS UiComponents
SOS UiComponentsSOS UiComponents
SOS UiComponents
 
ClojureScript in Magento 2 - MageTitansMCR 2017
ClojureScript in Magento 2 - MageTitansMCR 2017ClojureScript in Magento 2 - MageTitansMCR 2017
ClojureScript in Magento 2 - MageTitansMCR 2017
 
Lizards & Pumpkins Catalog Replacement at mm17de
Lizards & Pumpkins Catalog Replacement at mm17deLizards & Pumpkins Catalog Replacement at mm17de
Lizards & Pumpkins Catalog Replacement at mm17de
 
Stories from the other side
Stories from the other sideStories from the other side
Stories from the other side
 
The beautiful Magento module - MageTitans 2014
The beautiful Magento module - MageTitans 2014The beautiful Magento module - MageTitans 2014
The beautiful Magento module - MageTitans 2014
 

Kürzlich hochgeladen

WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...masabamasaba
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is insideshinachiaurasa2
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastPapp Krisztián
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...masabamasaba
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Hararemasabamasaba
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benonimasabamasaba
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...masabamasaba
 

Kürzlich hochgeladen (20)

Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 

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