Commit 01c3f715 authored by Ivan Chepurnyi's avatar Ivan Chepurnyi

! closes feature #56 "Set mock to Magento factories"

! closes feature #55 "Create mock by class alias"
parent d6d016a1
......@@ -32,6 +32,9 @@ class EcomDev_PHPUnit_Model_App extends Mage_Core_Model_App
// Admin store code
const ADMIN_STORE_CODE = 'admin';
const REGISTRY_PATH_LAYOUT_SINGLETON = '_singleton/core/layout';
const XML_PATH_LAYOUT_MODEL_FOR_TEST = 'phpunit/suite/layout/model';
/**
* Old configuration model to be returned back
* after unit tests are finished
......@@ -122,8 +125,15 @@ class EcomDev_PHPUnit_Model_App extends Mage_Core_Model_App
*/
public function initTest()
{
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
// If garbage collector is not enabled,
// we enable it for tests
if (!gc_enabled()) {
gc_enable();
}
}
$this->_config = Mage::getConfig();
$this->_config->setOptions($options);
$this->_initBaseConfig();
$this->_initCache();
......@@ -152,6 +162,12 @@ class EcomDev_PHPUnit_Model_App extends Mage_Core_Model_App
Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
}
$layoutModel = Mage::getModel(
$this->getConfig()->getNode(self::XML_PATH_LAYOUT_MODEL_FOR_TEST)
);
Mage::register(self::REGISTRY_PATH_LAYOUT_SINGLETON, $layoutModel, true);
return $this;
}
......
......@@ -31,6 +31,13 @@ class EcomDev_PHPUnit_Model_Config extends Mage_Core_Model_Config
*/
protected $_scopeSnapshot = null;
/**
* List of replaced instance creation
*
* @return array
*/
protected $_replaceInstanceCreation = array();
/**
* Load config data from DB
*
......@@ -47,6 +54,62 @@ class EcomDev_PHPUnit_Model_Config extends Mage_Core_Model_Config
return $this;
}
/**
* Replaces creation of some instance by mock object
*
*
* @param string $type
* @param string $classAlias
* @param PHPUnit_Framework_MockObject_MockObject|PHPUnit_Framework_MockObject_MockBuilder $mock
* @return EcomDev_PHPUnit_Model_Config
*/
public function replaceInstanceCreation($type, $classAlias, $mock)
{
$this->_replaceInstanceCreation[$type][$classAlias] = $mock;
return $this;
}
/**
* Flushes instance creation instruction list
*
* @return EcomDev_PHPUnit_Model_Config
*/
public function flushReplaceInstanceCreation()
{
$this->_replaceInstanceCreation = array();
return $this;
}
/**
* Overriden for test case model instance creation mocking
*
* (non-PHPdoc)
* @see Mage_Core_Model_Config::getModelInstance()
*/
public function getModelInstance($modelClass='', $constructArguments=array())
{
if (!isset($this->_replaceInstanceCreation['model'][$modelClass])) {
return parent::getModelInstance($modelClass='', $constructArguments=array());
}
return $this->_replaceInstanceCreation['model'][$modelClass];
}
/**
* Overriden for test case model instance creation mocking
*
* (non-PHPdoc)
* @see Mage_Core_Model_Config::getModelInstance()
*/
public function getResourceModelInstance($modelClass='', $constructArguments=array())
{
if (!isset($this->_replaceInstanceCreation['resource_model'][$modelClass])) {
return parent::getResourceModelInstance($modelClass='', $constructArguments=array());
}
return $this->_replaceInstanceCreation['resource_model'][$modelClass];
}
/**
* Loads scope snapshot
*
......
<?php
// Loading Spyc yaml parser,
// becuase Symfony component is not working propertly with nested
require_once 'Spyc/spyc.php';
class EcomDev_PHPUnit_Model_Expectation
implements EcomDev_PHPUnit_Model_Expectation_Interface
{
/**
* List of created data object ids by path format
*
* @var array
*/
protected $_dataObjectIds = array();
/**
* Loaded data from Yaml files
*
* @var Varien_Object
*/
protected $_loadedData = null;
/**
* Data object used for managing
* expectation data
*
* @var string
*/
protected $_dataObjectClassAlias = 'ecomdev_phpunit/expectation_object';
/**
* Returns class alias for fixture data object
*
* @return string
*/
public function getDataObjectClassAlias()
{
return $this->_dataObjectClassAlias;
}
/**
* Retrieves data object for a particular path format
*
* @see EcomDev_PHPUnit_Model_Expectation_Interface::getDataObject()
*/
public function getDataObject($pathFormat = null, $args = array())
{
if ($pathFormat === null) {
return $this->_loadedData;
}
$argsHash = $pathFormat . '_' . md5(serialize($args));
// Check already created objects by path
if (!isset($this->_dataObjectIds[$argsHash])) {
if ($args) {
array_unshift($args, $pathFormat);
$dataPath = call_user_func_array('sprintf', $args);
} else {
$dataPath = $pathFormat;
}
$data = $this->_loadedData->getData($dataPath);
if (!is_array($data)) {
throw new InvalidArgumentException(
'Argument values for specifying special scope of expectations should be presented '
. ' in expectation file and should be an associative list (path: "' . $dataPath . '")'
);
}
$this->_dataObjectIds[$argsHash] = Mage::objects()->save(
Mage::getModel($this->getDataObjectClassAlias(), $data)
);
}
return Mage::objects($this->_dataObjectIds[$argsHash]);
}
/**
* Applies loaded data
*
* @see EcomDev_PHPUnit_Model_Test_Loadable_Interface::apply()
*/
public function apply()
{
// For now it does nothing :(
return $this;
}
/**
* Removes objects created in object cache
* Clears loaded data property
*
* @see EcomDev_PHPUnit_Model_Test_Loadable_Interface::discard()
*/
public function discard()
{
foreach ($this->_dataObjectIds as $objectId) {
Mage::objects()->delete($objectId);
}
$this->_dataObjectIds = array();
$this->_loadedData = null;
return $this;
}
/**
* Check that expectations is loaded
*
* @return boolean
*/
public function isLoaded()
{
return $this->_loadedData !== null;
}
/**
* Loads expected data from test case annotations
*
* @see EcomDev_PHPUnit_Model_Test_Loadable_Interface::loadByTestCase()
*/
public function loadByTestCase(EcomDev_PHPUnit_Test_Case $testCase)
{
$expectations = $testCase->getAnnotationByName('loadExpectation');
if (!$expectations) {
$expectations[] = null;
}
$expectationData = array();
foreach ($expectations as $expectation) {
if (empty($expectation)) {
$expectation = null;
}
$expectationFile = $testCase->getYamlFilePath('expectations', $expectation);
if (!$expectationFile) {
$text = 'There was no expectation defined for current test case';
if ($expectation) {
$text = sprintf('Cannot load expectation %s', $expectation);
}
throw new RuntimeException($text);
}
$expectationData = array_merge_recursive(
$expectationData, Spyc::YAMLLoad($expectationFile)
);
}
$this->_loadedData = new Varien_Object($expectationData);
return $this;
}
}
\ No newline at end of file
<?php
/**
* PHP Unit test suite for Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category EcomDev
* @package EcomDev_PHPUnit
* @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
*/
/**
* Interface for fixture model
* Can be used for creation of
* absolutely different implementation of fixture,
* then current one.
*
*/
interface EcomDev_PHPUnit_Model_Expectation_Interface extends EcomDev_PHPUnit_Model_Test_Loadable_Interface
{
/**
* Returns data object with expectations
*
* @param string $pathFormat
* @param array $args arguments for format function
* @return EcomDev_PHPUnit_Model_Expectation_Object
*/
public function getDataObject($pathFormat = null, $args = array());
/**
* Check is expectation loaded
*
* @return boolean
*/
public function isLoaded();
}
\ No newline at end of file
<?php
/**
* PHP Unit test suite for Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category EcomDev
* @package EcomDev_PHPUnit
* @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
*/
/**
* Expectation data object used for retrieving of data from expectations array
* Created to make possible iteration of expected data,
* for instance if you have list of orders
*
*/
class EcomDev_PHPUnit_Model_Expectation_Object
extends Varien_Object
implements Iterator
{
protected $_createdObjectIds = array();
/**
* Current key in iterator
*
* @var array
*/
protected $_iterationKeys = array();
/**
* If current element is an array,
* then it will be automatically wrapped by
* the same class instance as this one
*
* @see Iterator::current()
* @return null|int|string|boolean|decimal|EcomDev_PHPUnit_Model_Expectation_Object
*/
public function current()
{
if ($this->key() === null) {
return null;
}
$current = $this->_data[$this->key()];
if (is_array($current)) {
$newObject = new self($current);
$this->_createdObjectIds = Mage::objects()
->save($current);
return $newObject;
}
return $current;
}
/* (non-PHPdoc)
* @see Iterator::key()
*/
public function key()
{
return current($this->_iterationKeys);
}
/* (non-PHPdoc)
* @see Iterator::next()
*/
public function next()
{
next($this->_iterationKeys);
}
/* (non-PHPdoc)
* @see Iterator::rewind()
*/
public function rewind()
{
$this->_iterationKeys = $this->keys();
}
/* (non-PHPdoc)
* @see Iterator::valid()
*/
public function valid()
{
return key($this->_iterationKeys) !== null;
}
/**
* Object destructor removes
* created objects from object pool
*
*
*/
public function __destruct()
{
if (!empty($this->_createdObjectIds)) {
foreach ($this->_createdObjectIds as $objectId) {
Mage::objects()->delete($objectId);
}
}
}
/**
* Returns data array keys
*
* @return array
*/
public function keys()
{
return array_keys($this->_data);
}
/**
* Returns data array values
*
* @return array
*/
public function values()
{
return array_values($this->_data);
}
}
......@@ -26,7 +26,9 @@ require_once 'Spyc/spyc.php';
* Created for operations with different fixture types
*
*/
class EcomDev_PHPUnit_Model_Fixture extends Mage_Core_Model_Abstract
class EcomDev_PHPUnit_Model_Fixture
extends Mage_Core_Model_Abstract
implements EcomDev_PHPUnit_Model_Fixture_Interface
{
// Configuration path for eav loaders
const XML_PATH_FIXTURE_EAV_LOADERS = 'phpunit/suite/fixture/eav';
......@@ -114,6 +116,36 @@ class EcomDev_PHPUnit_Model_Fixture extends Mage_Core_Model_Abstract
return $this;
}
/**
* Loads fixture from test case annotations
*
* @param EcomDev_PHPUnit_Test_Case $testCase
* @return EcomDev_PHPUnit_Model_Fixture
*/
public function loadByTestCase(EcomDev_PHPUnit_Test_Case $testCase)
{
$fixtures = $testCase->getAnnotationByName(
'loadFixture',
array('class', 'method')
);
foreach ($fixtures as $fixture) {
if (empty($fixture)) {
$fixture = null;
}
$filePath = $testCase->getYamlFilePath('fixtures', $fixture);
if (!$filePath) {
throw new RuntimeException('Unable to load fixture for test');
}
$this->loadYaml($filePath);
}
return $this;
}
/**
* Load YAML file
*
......
<?php
/**
* PHP Unit test suite for Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category EcomDev
* @package EcomDev_PHPUnit
* @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
*/
/**
* Interface for fixture model
* Can be used for creation of
* absolutely different implementation of fixture,
* then current one.
*
*/
interface EcomDev_PHPUnit_Model_Fixture_Interface extends EcomDev_PHPUnit_Model_Test_Loadable_Interface
{
/**
* Sets fixture options
*
* @param array $options
* @return EcomDev_PHPUnit_Model_Fixture_Interface
*/
public function setOptions(array $options);
}
\ No newline at end of file
<?php
/**
* PHP Unit test suite for Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category EcomDev
* @package EcomDev_PHPUnit
* @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
*/
/**
* Layout model that adds additional functionality
* for testing the layout itself
*
*/
class EcomDev_PHPUnit_Model_Layout extends Mage_Core_Model_Layout
{
/**
* List of replaced blocks creation
*
* @return array
*/
protected $_replaceBlockCreation = array();
/**
* Replaces creation of some block by mock object
*
* @param string $classAlias
* @param PHPUnit_Framework_MockObject_MockObject|PHPUnit_Framework_MockObject_MockBuilder $mock
* @return EcomDev_PHPUnit_Model_Layout
*/
public function replaceBlockCreation($classAlias, $mock)
{
$this->_replaceBlockCreation[$classAlias] = $mock;
return $this;
}
/**
* Flushes instance creation instruction list
*
* @return EcomDev_PHPUnit_Model_Layout
*/
public function flushReplaceBlockCreation()
{
$this->_replaceBlockCreation = array();
return $this;
}
/**
* Overriden for possibility of replacing a block by mock object
* (non-PHPdoc)
* @see Mage_Core_Model_Layout::_getBlockInstance()
*/
protected function _getBlockInstance($block, array $attributes=array())
{
if (!isset($this->_replaceBlockCreation[$block])) {
return parent::_getBlockInstance($block, $attributes);
}
return $this->_replaceBlockCreation[$block];
}
/**
* Resets layout instance properties
*
* @return EcomDev_PHPUnit_Model_Layout
*/
public function reset()
{
$this->setXml(simplexml_load_string('<layout/>', $this->_elementClass));
$this->_update = Mage::getModel('core/layout_update');
$this->_area = null;
$this->_helpers = array();
$this->_directOutput = false;
$this->_output = array();
foreach ($this->_blocks as $block) {
// Remove references between blocks
$block->setParentBlock(null);
$block->setMessageBlock(null);
$block->unsetChildren();
}
$this->_blocks = array();
$this->flushReplaceBlockCreation();
return $this;
}
}
<?php
/**
* PHP Unit test suite for Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category EcomDev
* @package EcomDev_PHPUnit
* @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
*/
/**
* Interface for loadable test environment data
*
*/
interface EcomDev_PHPUnit_Model_Test_Loadable_Interface
{
/**
* Loads external data by test case instance
*
* @param EcomDev_PHPUnit_Test_Case $testCase
* @return EcomDev_PHPUnit_Model_Test_Loadable_Interface
*/
public function loadByTestCase(EcomDev_PHPUnit_Test_Case $testCase);
/**
* Applies external data
*
* @return EcomDev_PHPUnit_Model_Test_Loadable_Interface
*/
public function apply();
/**
* Reverts applied data
*
* @return EcomDev_PHPUnit_Model_Test_Loadable_Interface
*/
public function discard();
}
......@@ -51,9 +51,16 @@
<helpers>Helper</helpers>
<blocks>Block</blocks>
</groups>
<!-- Test suite that will be used for creation of each of the tests -->
<test_suite>EcomDev_PHPUnit_Test_Suite_Group</test_suite>
<layout>
<model>ecomdev_phpunit/layout</model>
</layout>
<expectation>
<!-- Default model for loading of expectations -->
<model>ecomdev_phpunit/expectation</model>
</expectation>
<fixture>
<!-- Default model for loading of fixtures -->
<model>ecomdev_phpunit/fixture</model>
<eav>
<!-- Here goes the list of fixture loaders for EAV
If no fixture loader is specified for entity, then default will be used
......
<?php
/**
* PHP Unit test suite for Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category EcomDev
* @package EcomDev_PHPUnit
* @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
*/
class EcomDev_Utils_Reflection
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment