diff --git a/app/code/community/EcomDev/PHPUnit/Model/Fixture/Processor/Eav.php b/app/code/community/EcomDev/PHPUnit/Model/Fixture/Processor/Eav.php
index 1de02921..2094b1a7 100644
--- a/app/code/community/EcomDev/PHPUnit/Model/Fixture/Processor/Eav.php
+++ b/app/code/community/EcomDev/PHPUnit/Model/Fixture/Processor/Eav.php
@@ -89,10 +89,15 @@ public function apply(array $data, $key, EcomDev_PHPUnit_Model_FixtureInterface
$this->getResource()->beginTransaction();
foreach ($data as $entityType => $values) {
- $eavLoaders[] = $this->_getEavLoader($entityType)
+ $eavLoaders[$entityType] = $this->_getEavLoader($entityType)
->setFixture($fixture)
- ->setOptions($fixture->getOptions())
- ->loadEntity($entityType, $values);
+ ->setOptions($fixture->getOptions());
+
+ if ($eavLoaders[$entityType] instanceof EcomDev_PHPUnit_Model_Mysql4_Fixture_RestoreAwareInterface) {
+ $eavLoaders[$entityType]->saveData($entityType);
+ }
+
+ $eavLoaders[$entityType]->loadEntity($entityType, $values);
}
$this->getResource()->commit();
@@ -126,16 +131,35 @@ public function discard(array $data, $key, EcomDev_PHPUnit_Model_FixtureInterfac
EcomDev_PHPUnit_Model_FixtureInterface::SCOPE_SHARED);
}
+ $typesToRestore = array();
$this->getResource()->beginTransaction();
foreach (array_keys($data) as $entityType) {
+ $eavLoader = $this->_getEavLoader($entityType);
+
if (in_array($entityType, $ignoreCleanUp)) {
+ if ($eavLoader instanceof EcomDev_PHPUnit_Model_Mysql4_Fixture_RestoreAwareInterface) {
+ $eavLoader->clearData($entityType);
+ }
continue;
}
- $this->_getEavLoader($entityType)
- ->cleanEntity($entityType);
- }
+
+ $eavLoader->cleanEntity($entityType);
+ if ($eavLoader instanceof EcomDev_PHPUnit_Model_Mysql4_Fixture_RestoreAwareInterface) {
+ $typesToRestore[$entityType] = $eavLoader;
+ }
+ }
$this->getResource()->commit();
+
+ if ($typesToRestore) {
+ $this->getResource()->beginTransaction();
+ foreach ($typesToRestore as $entityType => $eavLoader) {
+ $eavLoader->restoreData($entityType)
+ ->clearData($entityType);
+ }
+ $this->getResource()->commit();
+ }
+
return $this;
}
}
\ No newline at end of file
diff --git a/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/AbstractEav.php b/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/AbstractEav.php
index a24eac03..925caf20 100644
--- a/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/AbstractEav.php
+++ b/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/AbstractEav.php
@@ -22,7 +22,10 @@
*/
abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_AbstractEav
extends EcomDev_PHPUnit_Model_Mysql4_Fixture_AbstractComplex
+ implements EcomDev_PHPUnit_Model_Mysql4_Fixture_RestoreAwareInterface
{
+ const RESTORE_KEY = 'restore_%s_data';
+
/**
* List of indexers required to build
*
@@ -37,6 +40,20 @@ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_AbstractEav
*/
protected $_originalIndexers = array();
+ /**
+ * List of tables that should be restored after run
+ *
+ * @var string[]
+ */
+ protected $_restoreTables = array();
+
+ /**
+ * Default data for eav entity
+ *
+ * @var array
+ */
+ protected $_defaultData = array();
+
/**
* Retrieve required indexers for re-building
*
@@ -99,6 +116,69 @@ public function cleanEntity($entityType)
return $this;
}
+
+ /**
+ * Saves data for restoring it after fixture has been cleaned up
+ *
+ * @param string $code storage code
+ * @return $this
+ */
+ public function saveData($code)
+ {
+ if ($this->_restoreTables) {
+ $storageKey = sprintf(self::RESTORE_KEY, $code);
+ $data = array();
+ foreach ($this->_restoreTables as $table) {
+ $select = $this->_getReadAdapter()->select();
+ $select->from($table);
+ $data[$table] = $this->_getReadAdapter()->fetchAll($select);
+ }
+ $this->_fixture->setStorageData($storageKey, $data);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Restored saved data
+ *
+ * @param string $code storage code
+ * @return $this
+ */
+ public function restoreData($code)
+ {
+ if ($this->_restoreTables) {
+ $storageKey = sprintf(self::RESTORE_KEY, $code);
+ $data = $this->_fixture->getStorageData($storageKey);
+ foreach ($this->_restoreTables as $table) {
+ if (!empty($data[$table])) {
+ $this->_getWriteAdapter()->insertOnDuplicate(
+ $table,
+ $data[$table]
+ );
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Clears storage from stored backup data
+ *
+ * @param $code
+ * @return $this
+ */
+ public function clearData($code)
+ {
+ if ($this->_restoreTables) {
+ $storageKey = sprintf(self::RESTORE_KEY, $code);
+ $this->_fixture->setStorageData($storageKey, array());
+ }
+
+ return $this;
+ }
+
/**
* Loads EAV data into DB tables
*
@@ -139,16 +219,43 @@ public function loadEntity($entityType, $values)
// and rows list as value
// See getCustomTableRecords
$customValues = array();
+
+ if ($this->_defaultData) {
+ $dataToInsert = $this->_defaultData;
+ // Prevent insertion of default data,
+ // if there is already data available
+ foreach ($values as $index => $row) {
+ if (isset($row[$this->_getEntityIdField($entityTypeModel)])
+ && isset($dataToInsert[$this->_getEntityIdField($entityTypeModel)])) {
+ $dataToInsert = array();
+ break;
+ }
+ }
+
+ foreach ($dataToInsert as $row) {
+ array_unshift($values, $row);
+ }
+ }
+
- foreach ($values as $index => &$row) {
+ foreach ($values as $index => $row) {
if (!isset($row[$this->_getEntityIdField($entityTypeModel)])) {
throw new RuntimeException('Entity Id should be specified in EAV fixture');
}
// Fulfill necessary information
- $row['entity_type_id'] = $entityTypeModel->getEntityTypeId();
+ $values[$index]['entity_type_id'] = $entityTypeModel->getEntityTypeId();
+ $row = $values[$index];
+
if (!isset($row['attribute_set_id'])) {
- $row['attribute_set_id'] = $entityTypeModel->getDefaultAttributeSetId();
+ $defaultAttributeSet = $entityTypeModel->getDefaultAttributeSetId();
+
+ // Fix Magento core issue with attribute set information for customer and its address
+ if (in_array($entityType, array('customer', 'customer_address'))) {
+ $defaultAttributeSet = 0;
+ }
+
+ $values[$index]['attribute_set_id'] = $defaultAttributeSet;
}
// Preparing entity table record
diff --git a/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Category.php b/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Category.php
index 050f9c82..adcd4168 100644
--- a/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Category.php
+++ b/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Category.php
@@ -23,9 +23,36 @@
*/
class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Catalog_Category extends EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Catalog_Abstract
{
+ const XML_PATH_DEFAULT_DATA = 'phpunit/suite/fixture/default_data/category';
+
protected $_requiredIndexers = array(
'catalog_category_flat'
);
+
+ protected function _construct()
+ {
+ parent::_construct();
+ $defaultData = Mage::getConfig()->getNode(self::XML_PATH_DEFAULT_DATA);
+
+ if ($defaultData) {
+ foreach ($defaultData->children() as $item) {
+ if (!isset($item->entity_id)) {
+ continue;
+ }
+
+ $entityId = (string)$item->entity_id;
+ $this->_defaultData[$entityId] = array();
+ foreach ($item->children() as $value) {
+ $this->_defaultData[$entityId][$value->getName()] = (string)$value;
+ }
+ }
+ }
+
+ $this->_restoreTables[] = $this->getTable('catalog/category');
+ foreach (array('datetime', 'decimal', 'int', 'text', 'varchar') as $suffix) {
+ $this->_restoreTables[] = $this->getTable(array('catalog/category', $suffix));
+ }
+ }
/**
* Overridden to add easy fixture loading for product associations
diff --git a/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/RestoreAwareInterface.php b/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/RestoreAwareInterface.php
new file mode 100644
index 00000000..9568a382
--- /dev/null
+++ b/app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/RestoreAwareInterface.php
@@ -0,0 +1,28 @@
+helperMockClassAlias('model', $classAlias, $methods, $constructorArgs);
}
+ /**
+ * Creates a mock for a resource model by its class alias
+ *
+ * @param string $classAlias
+ * @param array $methods
+ * @param array $constructorArgs
+ *
+ * @return EcomDev_PHPUnit_Mock_Proxy
+ */
+ public function helperMockResourceModel($classAlias, array $methods = array(), array $constructorArgs = array())
+ {
+ return $this->helperMockClassAlias('resource_model', $classAlias, $methods, $constructorArgs);
+ }
+
+
/**
* Creates a mock for a block by its class alias
*
diff --git a/app/code/community/EcomDev/PHPUnit/Test/Case/Util.php b/app/code/community/EcomDev/PHPUnit/Test/Case/Util.php
index a04ab885..72fd9f54 100644
--- a/app/code/community/EcomDev/PHPUnit/Test/Case/Util.php
+++ b/app/code/community/EcomDev/PHPUnit/Test/Case/Util.php
@@ -501,7 +501,7 @@ public static function getGroupedClassName($type, $classAlias)
public static function getGroupedClassMockBuilder(PHPUnit_Framework_TestCase $testCase, $type, $classAlias)
{
$className = self::getGroupedClassName($type, $classAlias);
- return new EcomDev_PHPUnit_Mock_Proxy($testCase, $className);
+ return new EcomDev_PHPUnit_Mock_Proxy($testCase, $className, $classAlias);
}
/**
@@ -511,6 +511,7 @@ public static function getGroupedClassMockBuilder(PHPUnit_Framework_TestCase $te
public static function setUp()
{
self::app()->resetDispatchedEvents();
+ self::$originalStore = Mage::app()->getStore()->getCode();
}
/**
diff --git a/app/code/community/EcomDev/PHPUnit/Test/Listener.php b/app/code/community/EcomDev/PHPUnit/Test/Listener.php
index aa8ee806..f9d043f8 100644
--- a/app/code/community/EcomDev/PHPUnit/Test/Listener.php
+++ b/app/code/community/EcomDev/PHPUnit/Test/Listener.php
@@ -173,6 +173,9 @@ public function endTest(PHPUnit_Framework_Test $test, $time)
));
if ($test instanceof PHPUnit_Framework_TestCase) {
+ EcomDev_PHPUnit_Helper::tearDown();
+ EcomDev_PHPUnit_Test_Case_Util::tearDown();
+
EcomDev_PHPUnit_Test_Case_Util::getFixture(get_class($test))
->setScope(EcomDev_PHPUnit_Model_FixtureInterface::SCOPE_LOCAL)
->discard(); // Clear applied fixture
@@ -180,9 +183,6 @@ public function endTest(PHPUnit_Framework_Test $test, $time)
if (EcomDev_PHPUnit_Test_Case_Util::getExpectation(get_class($test))->isLoaded()) {
EcomDev_PHPUnit_Test_Case_Util::getExpectation(get_class($test))->discard();
}
-
- EcomDev_PHPUnit_Test_Case_Util::tearDown();
- EcomDev_PHPUnit_Helper::tearDown();
}
Mage::dispatchEvent('phpunit_test_end_after', array(
diff --git a/app/code/community/EcomDev/PHPUnit/etc/config.xml b/app/code/community/EcomDev/PHPUnit/etc/config.xml
index 0d5f02b4..d032fe57 100644
--- a/app/code/community/EcomDev/PHPUnit/etc/config.xml
+++ b/app/code/community/EcomDev/PHPUnit/etc/config.xml
@@ -114,6 +114,37 @@
ecomdev_phpunit/fixture_eav_catalog_product
ecomdev_phpunit/fixture_eav_catalog_category
+
+
+
+ 1
+ 0
+ 1
+ 0
+ 0
+ 1
+ Root Catalog
+ root-catalog
+ 1
+ 0
+ 0
+
+
+ 2
+ 1
+ 1/2
+ 1
+ 1
+ 0
+ Default Category
+ default-category
+ 1
+ 0
+ PRODUCTS
+ 1
+
+
+
diff --git a/lib/EcomDev/PHPUnit/Mock/Proxy.php b/lib/EcomDev/PHPUnit/Mock/Proxy.php
index a1028ffd..53e797dc 100644
--- a/lib/EcomDev/PHPUnit/Mock/Proxy.php
+++ b/lib/EcomDev/PHPUnit/Mock/Proxy.php
@@ -29,6 +29,26 @@ class EcomDev_PHPUnit_Mock_Proxy
{
protected $mockInstance;
+ /**
+ * Original mocked class alias
+ *
+ * @var string
+ */
+ protected $classAlias;
+
+ /**
+ * Added class alias as property
+ *
+ * @param PHPUnit_Framework_TestCase $testCase
+ * @param array|string $type
+ * @param null $classAlias
+ */
+ public function __construct(PHPUnit_Framework_TestCase $testCase, $type, $classAlias = null)
+ {
+ parent::__construct($testCase, $type);
+ $this->classAlias = $classAlias;
+ }
+
/**
* Adds method name to a mock builder
*
@@ -113,6 +133,18 @@ public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher
return $this->getMockInstance()->expects($matcher);
}
+ /**
+ * Invokes replaceByMock test util method with current mock object proxy instance
+ *
+ * @param $type
+ * @return $this
+ */
+ public function replaceByMock($type)
+ {
+ EcomDev_PHPUnit_Test_Case_Util::replaceByMock($type, $this->classAlias, $this);
+ return $this;
+ }
+
/**
* Returns invocation mocker for
*