SlideShare une entreprise Scribd logo
1  sur  110
Télécharger pour lire hors ligne
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

Contenu connexe

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

Writing Testable Code (for Magento 1 and 2)
Writing Testable Code (for Magento 1 and 2)Writing Testable Code (for Magento 1 and 2)
Writing Testable Code (for Magento 1 and 2)vinaikopp
 
Getting your Hands Dirty Testing Magento 2 (at London Meetup)
Getting your Hands Dirty Testing Magento 2 (at London Meetup)Getting your Hands Dirty Testing Magento 2 (at London Meetup)
Getting your Hands Dirty Testing Magento 2 (at London Meetup)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
 
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]
 
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
 
Extension Submission to Marketplace
Extension Submission to MarketplaceExtension Submission to Marketplace
Extension Submission to MarketplaceWagento Kangiya
 
Dependency Injection Extended: the way to advanced Magento 2 development
Dependency Injection Extended: the way to advanced Magento 2 developmentDependency Injection Extended: the way to advanced Magento 2 development
Dependency Injection Extended: the way to advanced Magento 2 developmentAndreas von Studnitz
 
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
 
Modern Module Architecture
Modern Module ArchitectureModern Module Architecture
Modern Module Architecturevinaikopp
 
Architecture in-the-small-slides
Architecture in-the-small-slidesArchitecture in-the-small-slides
Architecture in-the-small-slidesvinaikopp
 
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
 
Secure input and output handling - Meet Magento Romania 2016
Secure input and output handling - Meet Magento Romania 2016Secure input and output handling - Meet Magento Romania 2016
Secure input and output handling - Meet Magento Romania 2016Anna Völkl
 
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
 
PCI Compliance for Hipsters
PCI Compliance for HipstersPCI Compliance for Hipsters
PCI Compliance for HipstersPhillip Jackson
 
Microsoft TechDays 2016 in Baden
Microsoft TechDays 2016 in BadenMicrosoft TechDays 2016 in Baden
Microsoft TechDays 2016 in BadenFabian Gosebrink
 
SOS UiComponents
SOS UiComponentsSOS UiComponents
SOS UiComponentsvinaikopp
 
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016Tatiane Aguirres Nogueira
 
Shuki Mann - LIXFIX (All Things Data 2015)
Shuki Mann - LIXFIX (All Things Data 2015)Shuki Mann - LIXFIX (All Things Data 2015)
Shuki Mann - LIXFIX (All Things Data 2015)Shuki Mann
 

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

Writing Testable Code (for Magento 1 and 2)
Writing Testable Code (for Magento 1 and 2)Writing Testable Code (for Magento 1 and 2)
Writing Testable Code (for Magento 1 and 2)
 
Getting your Hands Dirty Testing Magento 2 (at London Meetup)
Getting your Hands Dirty Testing Magento 2 (at London Meetup)Getting your Hands Dirty Testing Magento 2 (at London Meetup)
Getting your Hands Dirty Testing Magento 2 (at London Meetup)
 
Writing testable Code (MageTitans Mini 2016)
Writing testable Code (MageTitans Mini 2016)Writing testable Code (MageTitans Mini 2016)
Writing testable Code (MageTitans Mini 2016)
 
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
 
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
 
Extension Submission to Marketplace
Extension Submission to MarketplaceExtension Submission to Marketplace
Extension Submission to Marketplace
 
Dependency Injection Extended: the way to advanced Magento 2 development
Dependency Injection Extended: the way to advanced Magento 2 developmentDependency Injection Extended: the way to advanced Magento 2 development
Dependency Injection Extended: the way to advanced Magento 2 development
 
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
 
Modern Module Architecture
Modern Module ArchitectureModern Module Architecture
Modern Module Architecture
 
Architecture in-the-small-slides
Architecture in-the-small-slidesArchitecture in-the-small-slides
Architecture in-the-small-slides
 
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
 
Secure input and output handling - Meet Magento Romania 2016
Secure input and output handling - Meet Magento Romania 2016Secure input and output handling - Meet Magento Romania 2016
Secure input and output handling - Meet Magento Romania 2016
 
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
 
PCI Compliance for Hipsters
PCI Compliance for HipstersPCI Compliance for Hipsters
PCI Compliance for Hipsters
 
Microsoft TechDays 2016 in Baden
Microsoft TechDays 2016 in BadenMicrosoft TechDays 2016 in Baden
Microsoft TechDays 2016 in Baden
 
SOS UiComponents
SOS UiComponentsSOS UiComponents
SOS UiComponents
 
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016
 
GraphQL in Magento 2
GraphQL in Magento 2GraphQL in Magento 2
GraphQL in Magento 2
 
Shuki Mann - LIXFIX (All Things Data 2015)
Shuki Mann - LIXFIX (All Things Data 2015)Shuki Mann - LIXFIX (All Things Data 2015)
Shuki Mann - LIXFIX (All Things Data 2015)
 
Magento best practices
Magento best practicesMagento best practices
Magento best practices
 

Plus de vinaikopp

Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023vinaikopp
 
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
 
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
 

Plus de vinaikopp (8)

Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023Building Mage-OS - MageTitans 2023
Building Mage-OS - MageTitans 2023
 
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
 
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
 

Dernier

Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
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
 
%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 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...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
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park masabamasaba
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxAnnaArtyushina1
 
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 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
 
%+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 Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburgmasabamasaba
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2
 
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
 
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
 

Dernier (20)

Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
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
 
%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 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%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
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
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 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
 
%+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 Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
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
 
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...
 

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