Slide 1

Slide 1 text

Intégration continue, tests et automatisation

Slide 2

Slide 2 text

/me Consultant pour Sensio Labs http://alexandre-salome.fr – [email protected] twitter.com/alexandresalome cf Google, sinon Ancien Lillois ! Etudiant à Lille-1 Habité à Lille Fives Premier emploi Premier site en Magento

Slide 3

Slide 3 text

/you Qui a déjà travaillé avec Magento ?

Slide 4

Slide 4 text

/you Qui a déjà développé pour Magento ?

Slide 5

Slide 5 text

/you Qui a déjà fait des tests en Magento ?

Slide 6

Slide 6 text

Plan de la conférence • The Big Picture • Coder dans Magento • Les modules, à prendre ou à laisser • Automatiser son projet – Installation – Données par défaut – Tester son projet

Slide 7

Slide 7 text

THE BIG PICTURE

Slide 8

Slide 8 text

Le E-Commerce • Le marché le plus profitable – Jusqu’à 30 milliards d’euros en 2010 en France • Une habitude de consommation – 72% des français ont déjà acheté en ligne Source : http://www.journaldunet.com/cc/04_ecommerce/ecom_marche_fr.shtml

Slide 9

Slide 9 text

Créer un site E-Commerce • PHP – Os Commerce (si si, ça existe encore) – Prestashop – Magento • Autres langages – Ruby : Spree, Substruct – Python : ? • Platerforme : http://www.shopify.com

Slide 10

Slide 10 text

Créer un site E-Commerce • PHP – Os Commerce (si si, ça existe encore) – Prestashop – Magento • Autres langages – Ruby : Spree, Substruct – Pyhon : ? • Platerforme : http://www.shopify.com

Slide 11

Slide 11 text

Magento = Usine • Ne l’utilisez que si vous avez un gros besoin • N’hésitez pas à utiliser des solutions simples – Prestashop ? – Une plateforme ?

Slide 12

Slide 12 text

Bien développer un projet • Commencer par le plus critique • Automatiser tout ce qu’il peut l’être • Développer des fonctionnalités • Développer des tests • Maîtriser son application

Slide 13

Slide 13 text

Les frameworks • Fournir des outils • Travailler de manière standard • Des tests intégrés • Souplesse de l’application • Automatisation facilitée

Slide 14

Slide 14 text

Mais Magento • Peu de documentation • Code tiers assez « dirty » • Aucun test fourni • Application monolithique • Peu de support de qualité

Slide 15

Slide 15 text

Pourquoi ? Frameworks PHP Magento • Il en existe plusieurs – Symfony – Zend Framework – CakePHP – etc. • Communauté ouverte • Code totalement ouvert • Forums de support actifs • Très connu • Seule solution sur le marché – Pas pour les petites boutiques – Ensemble fonctionnel très complet • Varien = entreprise – Pas moyen de tester – Monétisation des extensions

Slide 16

Slide 16 text

Pourquoi ? Frameworks PHP Magento

Slide 17

Slide 17 text

DÉVELOPPER POUR MAGENTO

Slide 18

Slide 18 text

Développeur Magento • Un développeur Magento  Dur à trouver • Un bon développeur Magento  Encore plus dur à trouver Bien souvent, il faut le former  Coder dans Magento est donc coûteux

Slide 19

Slide 19 text

Les ressources Magento • Peu nombreuses – Site préféré : Alan Storm - http://alanstorm.com/ – Site de confiance : magentocommerce.com • Qualité variable – Toujours être critique – Tenter de copier le minimum – Moins de code = moins de bug

Slide 20

Slide 20 text

Assumez ! • Vous n’êtes pas « Expert Magento » (sauf si vous l’êtes vraiment) • Restez modeste – Maîtrisé = intégrer maquettes – Non-maîtrisé = créer des nouveaux modules Objectifs SMART KISS

Slide 21

Slide 21 text

Assumez ! • Vous n’êtes pas « Expert Magento » (sauf si vous l’êtes vraiment) • Restez modeste – Maîtrisé = intégrer maquettes – Non-maîtrisé = créer des nouveaux modules Specific Measurable Attainable Revelant Time-boxed Keep It Simple, Stupid

Slide 22

Slide 22 text

Séparation des métiers • Magento, c’est la boutique

Slide 23

Slide 23 text

Séparation des métiers • Magento, c’est la boutique • On ne fait pas tout dans la boutique

Slide 24

Slide 24 text

Séparation des métiers • Génération de code barre – Librairie PHP à part pour générer les images – API afin de coder moins dans Magento

Slide 25

Slide 25 text

Séparation des métiers • Location de produits – Gestion du planning sortie de Magento • Application tierce • API afin de coder moins dans Magento – Produit dans la boutique = ticket

Slide 26

Slide 26 text

Ne modifiez pas Magento • On ne modifie jamais les fichiers de Magento • On code dans : – app/code/local pour les modules – app/design/frontend/my-company Si vous modifiez le code de Magento, vous avez raté votre vie

Slide 27

Slide 27 text

LES MODULES, À PRENDRE OU À LAISSER

Slide 28

Slide 28 text

Pourquoi prendre un module ? Gagner du temps == Gagner de l’argent

Slide 29

Slide 29 text

Pourquoi laisser un module ? • Dépendance requise non désirée • Non-qualité du module • Il faut modifier son code  Perte de temps  Perte d’argent..

Slide 30

Slide 30 text

Soyez critique ! Qui connait l’extension Fontis ? (WYSIWYG pour Magento)

Slide 31

Slide 31 text

Lisez le code ! if(file_exists('../../../app/etc/local.xml')) { $xml = simplexml_load_file('../../../app/etc/local.xml'); $host = $xml->global->resources->default_setup->connection->host; $username = $xml->global->resources->default_setup->connection->username; $password = $xml->global->resources->default_setup->connection->password; $dbname = $xml->global->resources->default_setup->connection->dbname; $db = mysql_connect($host, $username, $password); mysql_select_db($dbname, $db); $result = mysql_fetch_assoc(mysql_query( "SELECT * FROM core_config_data WHERE path = 'fontis_wysiwyg/fckeditor/usecustomtoolbarjs'")); if($result) { $useCustomToolbarJS = $result['value']; } else { $useCustomToolbarJS = null; }

Slide 32

Slide 32 text

Lisez le code ! if(file_exists('../../../app/etc/local.xml')) { $xml = simplexml_load_file('../../../app/etc/local.xml'); $host = $xml->global->resources->default_setup->connection->host; $username = $xml->global->resources->default_setup->connection->username; $password = $xml->global->resources->default_setup->connection->password; $dbname = $xml->global->resources->default_setup->connection->dbname; $db = mysql_connect($host, $username, $password); mysql_select_db($dbname, $db); $result = mysql_fetch_assoc(mysql_query( "SELECT * FROM core_config_data WHERE path = 'fontis_wysiwyg/fckeditor/usecustomtoolbarjs'")); if($result) { $useCustomToolbarJS = $result['value']; } else { $useCustomToolbarJS = null; }

Slide 33

Slide 33 text

Lisez le code ! if(file_exists('../../../app/etc/local.xml')) { $xml = simplexml_load_file('../../../app/etc/local.xml'); $host = $xml->global->resources->default_setup->connection->host; $username = $xml->global->resources->default_setup->connection->username; $password = $xml->global->resources->default_setup->connection->password; $dbname = $xml->global->resources->default_setup->connection->dbname; $db = mysql_connect($host, $username, $password); mysql_select_db($dbname, $db); $result = mysql_fetch_assoc(mysql_query( "SELECT * FROM core_config_data WHERE path = 'fontis_wysiwyg/fckeditor/usecustomtoolbarjs'")); if($result) { $useCustomToolbarJS = $result['value']; } else { $useCustomToolbarJS = null; }

Slide 34

Slide 34 text

Lisez le code ! if(file_exists('../../../app/etc/local.xml')) { $xml = simplexml_load_file('../../../app/etc/local.xml'); $host = $xml->global->resources->default_setup->connection->host; $username = $xml->global->resources->default_setup->connection->username; $password = $xml->global->resources->default_setup->connection->password; $dbname = $xml->global->resources->default_setup->connection->dbname; $db = mysql_connect($host, $username, $password); mysql_select_db($dbname, $db); $result = mysql_fetch_assoc(mysql_query( "SELECT * FROM core_config_data WHERE path = 'fontis_wysiwyg/fckeditor/usecustomtoolbarjs'")); if($result) { $useCustomToolbarJS = $result['value']; } else { $useCustomToolbarJS = null; } Pas de cache

Slide 35

Slide 35 text

Ré-usinons !

Slide 36

Slide 36 text

Ré-usinons !

Slide 37

Slide 37 text

Ré-usinons !

Slide 38

Slide 38 text

Ré-usinons !

Slide 39

Slide 39 text

Ré-usinons !

Slide 40

Slide 40 text

Votre extension doit vous faire gagner du temps

Slide 41

Slide 41 text

AUTOMATISER SON PROJET

Slide 42

Slide 42 text

« Il n’est pas fainéant, il évite les efforts inutiles » Mme Cognon, enseignante à Wasquehal

Slide 43

Slide 43 text

Automatiser son projet Supposons une tâche X, on pose : D le temps requis pour réaliser X C le temps requis pour automatiser X T le nombre de fois qu’on fait X

Slide 44

Slide 44 text

Automatiser son projet Supposons une tâche X, on pose : D le temps requis pour réaliser X C le temps requis pour automatiser X T le nombre de fois qu’on fait X On automatise si D.T > C

Slide 45

Slide 45 text

Automatiser son projet Autrement dit : On automatise si ça fait gagner du temps

Slide 46

Slide 46 text

Automatiser son projet Concernés • Installation du projet • Données par défaut • Tests du projet Pas forcément concernés • Mise en production • Déploiement

Slide 47

Slide 47 text

Automatiser son projet Concernés • Installation du projet • Données par défaut • Tester son projet Pas forcément concernés • Mise en production • Déploiement

Slide 48

Slide 48 text

INSTALLATION DU PROJET

Slide 49

Slide 49 text

D.T • Pour installer Magento, il faut : – Créer la base de données – Passer dans les 5 étapes du « wizard » – Fixer les permissions de dossier

Slide 50

Slide 50 text

C • Pour l’automatiser, il faut : – Un script

Slide 51

Slide 51 text

Un script de 3 lignes echo 'CREATE DATABASE magento' | mysql –uroot chmod a+w app/etc var media media/import php -f install.php -- \ --license_agreement_accepted yes \ --locale fr_FR \ --timezone "Europe/Paris" \ --default_currency EUR \ --db_host "localhost" \ --db_name "magento" \ --db_user "root" \ --db_pass "" \ (etc.)

Slide 52

Slide 52 text

Automatiser l’installation https://github.com/alexandresalome/Magento/tree/proveit-install

Slide 53

Slide 53 text

Critique de la solution • Exemple simple • Configuration en dur • Non-acceptable pour un projet réel

Slide 54

Slide 54 text

Automatiser l’installation echo 'CREATE DATABASE magento' | mysql –uroot chmod a+w app/etc var media media/import php -f install.php -- \ --license_agreement_accepted yes \ --locale fr_FR \ --timezone "Europe/Paris" \ --default_currency EUR \ --db_host "localhost" \ --db_name "magento" \ --db_user "root" \ --db_pass "" \ (etc.)

Slide 55

Slide 55 text

Résultat concret

Slide 56

Slide 56 text

Installation terminée ?

Slide 57

Slide 57 text

DONNÉES PAR DÉFAUT

Slide 58

Slide 58 text

Pourquoi ?

Slide 59

Slide 59 text

Utiliser les données de production • Données sensibles • Données volumineuses • Risque d’envoyer des mails aux clients • Principe de sécurité

Slide 60

Slide 60 text

Données par défaut • Quelques produits • Données sémantiques pour tester son projet • Données dynamiques, donc manipulables • Non lié à la production

Slide 61

Slide 61 text

Configuration

Slide 62

Slide 62 text

Configuration $model = Mage::getModel('adminhtml/config_data') ->setSection('catalog') ->setGroups(array( 'custom_options' => array( 'fields' => array( 'use_calendar' => array('value' => 1), 'date_fields_order' => array('value' => array('d', 'm', 'y')), 'time_format' => array('value' => '24h'), 'year_range' => array('value' => array(1900, 2100)) ) ) )) ; $model->save();

Slide 63

Slide 63 text

Création d’une catégorie require_once __DIR__.'/app/Mage.php'; Mage::app(); $category = Mage::getModel('catalog/category'); $category->addData(array( 'name' => 'Voitures', 'is_active' => 1, 'url_key' => 'voitures' )); $parentCategory = Mage::getModel('catalog/category')- >loadByAttribute('name', 'Default Category'); $category->setPath($parentCategory->getPath()); $category->save();

Slide 64

Slide 64 text

Création d’un produit $product = Mage::getModel('catalog/product'); $product->setWebsiteIds(array(1)); $product->setSku('COURSE'); $product->setPrice(4000); $product->setAttributeSetId(4); $product->setCategoryIds(array(3)); $product->setTypeId('simple'); $product->setName('Voiture de course'); $product->setDescription('Voiture qui va vite, très vite'); $product->setShortDescription('Voiture rapide'); $product->setStatus(1); $product->setTaxClassId('2'); $product->setWeight(0); $product->setCreatedAt(strtotime('now')); $product->save(); $stockItem = Mage::getModel('cataloginventory/stock_item'); $stockItem->setData('is_in_stock', 1); $stockItem->setData('product_id', $product->getId()); $stockItem->setData('stock_id', 1); $stockItem->save();

Slide 65

Slide 65 text

Création d’un produit $product = Mage::getModel('catalog/product'); $product->setWebsiteIds(array(1)); $product->setSku('COURSE'); $product->setPrice(4000); $product->setAttributeSetId(4); $product->setCategoryIds(array(3)); $product->setTypeId('simple'); $product->setName('Voiture de course'); $product->setDescription('Voiture qui va vite, très vite'); $product->setShortDescription('Voiture rapide'); $product->setStatus(1); $product->setTaxClassId('2'); $product->setWeight(0); $product->setCreatedAt(strtotime('now')); $product->save(); $stockItem = Mage::getModel('cataloginventory/stock_item'); $stockItem->setData('is_in_stock', 1); $stockItem->setData('product_id', $product->getId()); $stockItem->setData('stock_id', 1); $stockItem->save();

Slide 66

Slide 66 text

Création d’un produit $product = Mage::getModel('catalog/product'); $product->setWebsiteIds(array(Mage::getModel('core/website')->load('base', 'code'))); $product->setSku('COURSE'); $product->setPrice(4000); $product->setAttributeSetId(Mage::getModel('eav/entity_attribute_set')->load($product->getResource()- >getTypeId(), 'entity_type_id')->getId()); $product->setCategoryIds(array(Mage::getModel('catalog/category')->loadByAttribute('name', 'Voitures')- >getId())); $product->setTypeId('simple'); $product->setName('Voiture de course'); $product->setDescription('Voiture qui va vite, très vite'); $product->setShortDescription('Voiture rapide'); $product->setStatus(1); $product->setTaxClassId(Mage::getModel('tax/class')->load('Taxable Goods', 'class_name')->getId()); $product->setWeight(0); $product->setCreatedAt(strtotime('now')); $product->save(); $stockItem = Mage::getModel('cataloginventory/stock_item'); $stockItem->setData('is_in_stock', 1); $stockItem->setData('product_id', $product->getId()); $stockItem->setData('stock_id', Mage::getModel('cataloginventory/stock')->load('Default', 'stock_name')); $stockItem->save();

Slide 67

Slide 67 text

Données par défaut https://github.com/alexandresalome/Magento/tree/proveit-fixtures

Slide 68

Slide 68 text

Conclusion des données • Beaucoup de cas – Localisation / Internationalisation • Gestion multi-boutiques • Internationalisation – Import de données à partir de existant – Liaison avec autre(s) application(s) Trop spécifique pour être générique Adaptez à votre projet

Slide 69

Slide 69 text

TESTER SON PROJET

Slide 70

Slide 70 text

Quoi tester ? • TOUT CE QUI PEUT PETER • Tout ce qui est pénible • Gagner du temps = gagner de l’argent • Passer ses journées à tester n’est pas gratifiant

Slide 71

Slide 71 text

Quoi pas tester ? • Ne pas retester Magento – On re-teste ce qu’on a surchargé – On re-teste ce dont on veut être sûr • Ne pas enfoncer portes ouvertes – Surtout unitairement • Les tests pour lesquels D.T < C – Test de paiement par CB, par exemple

Slide 72

Slide 72 text

Comment tester !? • Tests unitaires ? • Tests fonctionnels ?

Slide 73

Slide 73 text

Comment tester !? • Tests unitaires  cf conf Marc W. • Tests fonctionnels ?

Slide 74

Slide 74 text

Comment tester !? • Tests unitaires  cf conf Marc W. – Mocks, Stubs • Tests fonctionnels ?

Slide 75

Slide 75 text

Comment tester !? • Tests unitaires  cf conf Marc W. – Mocks, Stubs – Ce qu’il faut tester • Tests fonctionnels ?

Slide 76

Slide 76 text

Comment tester !? • Tests unitaires  cf conf Marc W. – Mocks, Stubs – Ce qu’il faut tester – Bonnes pratiques de développement • Tests fonctionnels ?

Slide 77

Slide 77 text

Comment tester !? • Tests unitaires  cf conf Marc W. – Mocks, Stubs – Ce qu’il faut tester – Bonnes pratiques de développement • Tests fonctionnels ?

Slide 78

Slide 78 text

Tests fonctionnels

Slide 79

Slide 79 text

Tests fonctionnels

Slide 80

Slide 80 text

Test du fonctionnement

Slide 81

Slide 81 text

Tests fonctionnels • Comment dire que votre site fonctionne ? • C’est une boutique en ligne – Je peux naviguer dans le catalogue – Je peux voir une fiche produit – Je peux l’ajouter à mon panier – Je peux réussir le tunnel de commande

Slide 82

Slide 82 text

Tests fonctionnels • Comment décrire ses tests ? • Solutions – Selenium – Sahi – Zombie • Format – Tests BDD (Behat?) – Tests PHPUnit

Slide 83

Slide 83 text

Tests fonctionnels Quelque soit la solution/le moyen choisi, le plus important reste le corps de vos tests

Slide 84

Slide 84 text

Tests fonctionnels La solution/le moyen dépendent du corps de vos tests.

Slide 85

Slide 85 text

Tests fonctionnels • Notre corps de tests – Je peux naviguer dans le catalogue – Je peux voir une fiche produit – Je peux l’ajouter à mon panier – Je peux réussir le tunnel de commande • Solution retenue – PHPUnit – Librairie Selenium PHP

Slide 86

Slide 86 text

Tests fonctionnels public function testCatalog() { self::$browser ->open('/')->waitForPageToLoad(self::TIMEOUT) ->click(Locator::linkContaining('Voitures')) ->waitForPageToLoad(self::TIMEOUT); $this->assertRegExp('/voitures\.html$/', self::$browser->getLocation()); $this->assertEquals('1 Item(s)', self::$browser->getText('css=p.amount')); }

Slide 87

Slide 87 text

Données par défaut https://github.com/alexandresalome/Magento/tree/proveit-tests

Slide 88

Slide 88 text

Tests fonctionnels Tant que mes tests passent, je suis certain qu’il est possible d’acheter sur mon site.

Slide 89

Slide 89 text

PS: INTÉGRATION CONTINUE

Slide 90

Slide 90 text

Intégration continue • Devenu possible grâce aux efforts préalable • Les requis sont là : – Installation automatisée – Jeu de données par défaut – Suite de tests PHPUnit • Le reste, ça reste du paramétrage dans vos CI

Slide 91

Slide 91 text

Conclusion

Slide 92

Slide 92 text

MERCI http://joind.in/4366