Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
EcomDev_PHPUnit
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Open
EcomDev_PHPUnit
Commits
e1a9e49c
Commit
e1a9e49c
authored
Jul 14, 2011
by
Ivan Chepurnyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
+ Shared Fixtures
! Improved performance of EAV and scope fixtures loading
parent
f3bb0dac
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
632 additions
and
92 deletions
+632
-92
app/code/community/EcomDev/PHPUnit/Model/App.php
app/code/community/EcomDev/PHPUnit/Model/App.php
+4
-0
app/code/community/EcomDev/PHPUnit/Model/Config.php
app/code/community/EcomDev/PHPUnit/Model/Config.php
+29
-27
app/code/community/EcomDev/PHPUnit/Model/Fixture.php
app/code/community/EcomDev/PHPUnit/Model/Fixture.php
+368
-44
app/code/community/EcomDev/PHPUnit/Model/Fixture/Interface.php
...ode/community/EcomDev/PHPUnit/Model/Fixture/Interface.php
+73
-0
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture.php
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture.php
+1
-1
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Abstract.php
...ity/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Abstract.php
+31
-0
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Product.php
...mDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Product.php
+0
-1
app/code/community/EcomDev/PHPUnit/Test/Case.php
app/code/community/EcomDev/PHPUnit/Test/Case.php
+109
-19
lib/EcomDev/Utils/Reflection.php
lib/EcomDev/Utils/Reflection.php
+17
-0
No files found.
app/code/community/EcomDev/PHPUnit/Model/App.php
View file @
e1a9e49c
...
...
@@ -48,6 +48,8 @@ class EcomDev_PHPUnit_Model_App extends Mage_Core_Model_App
const
REGISTRY_PATH_LAYOUT_SINGLETON
=
'_singleton/core/layout'
;
const
REGISTRY_PATH_DESIGN_PACKAGE_SINGLETON
=
'_singleton/core/design_package'
;
const
REGISTRY_PATH_SHARED_STORAGE
=
'test_suite_shared_storage'
;
const
XML_PATH_LAYOUT_MODEL_FOR_TEST
=
'phpunit/suite/layout/model'
;
const
XML_PATH_DESIGN_PACKAGE_MODEL_FOR_TEST
=
'phpunit/suite/design/package/model'
;
...
...
@@ -221,6 +223,8 @@ class EcomDev_PHPUnit_Model_App extends Mage_Core_Model_App
$designPackageModel
);
$this
->
loadAreaPart
(
self
::
AREA_TEST
,
self
::
AREA_PART_EVENTS
);
$this
->
replaceRegistry
(
self
::
REGISTRY_PATH_SHARED_STORAGE
,
new
Varien_Object
());
return
$this
;
}
...
...
app/code/community/EcomDev/PHPUnit/Model/Config.php
View file @
e1a9e49c
...
...
@@ -28,12 +28,18 @@ class EcomDev_PHPUnit_Model_Config extends Mage_Core_Model_Config
const
CHANGE_ME
=
'[change me]'
;
/**
* Scope snapshot without applied configurations,
* It is used for proper store/website/default loading on per store basis
* Scope snapshot with different levels of saving configuration
*
* @var Mage_Core_Model_Config_Base
*/
protected
$_scopeSnapshot
=
null
;
protected
$_scopeSnapshot
=
array
();
/**
* Scope snapshot for a particular test case
*
* @var Mage_Core_Model_Config_Base
*/
protected
$_localScopeSnapshot
=
null
;
/**
* List of replaced instance creation
...
...
@@ -51,7 +57,7 @@ class EcomDev_PHPUnit_Model_Config extends Mage_Core_Model_Config
{
if
(
$this
->
_isLocalConfigLoaded
&&
Mage
::
isInstalled
()
&&
$this
->
_scopeSnapshot
===
null
)
{
&&
empty
(
$this
->
_scopeSnapshot
)
)
{
$this
->
saveScopeSnapshot
();
}
parent
::
loadDb
();
...
...
@@ -141,43 +147,39 @@ class EcomDev_PHPUnit_Model_Config extends Mage_Core_Model_Config
*/
public
function
loadScopeSnapshot
()
{
if
(
$this
->
_scopeSnapshot
===
null
)
{
if
(
empty
(
$this
->
_scopeSnapshot
)
)
{
throw
new
RuntimeException
(
'Cannot load scope snapshot, because it was not saved before'
);
}
$scopeNode
=
$this
->
_scopeSnapshot
->
getNode
();
foreach
(
$scopeNode
->
children
()
as
$nodeName
=>
$values
)
{
// Remove somehow modified before xml node
unset
(
$this
->
getNode
()
->
$nodeName
);
// Add saved snapshot of configuration node
$this
->
getNode
()
->
addChild
(
$nodeName
);
$this
->
getNode
()
->
$nodeName
->
extend
(
$values
);
}
$scope
=
clone
end
(
$this
->
_scopeSnapshot
);
$this
->
_xml
=
$scope
;
return
$this
;
}
/**
* Saves current configuration snapshot,
* for pussible restoring in feature
* Flushes current scope snapshot level if it is not the last one
*
* @param array $nodesToSave list of nodes for saving data, by default it is 'default', 'webistes', 'stores'
* @return EcomDev_PHPUnit_Model_Config
*/
public
function
saveScopeSnapshot
(
$nodesToSave
=
array
(
'default'
,
'websites'
,
'stores'
)
)
public
function
flushScopeSnapshot
(
)
{
$this
->
_scopeSnapshot
=
clone
$this
->
_prototype
;
$this
->
_scopeSnapshot
->
loadString
(
'<config />'
);
$scopeNode
=
$this
->
_scopeSnapshot
->
getNode
();
foreach
(
$nodesToSave
as
$node
)
{
$scopeNode
->
addChild
(
$node
);
$scopeNode
->
{
$node
}
->
extend
(
$this
->
getNode
(
$node
),
true
);
if
(
count
(
$this
->
_scopeSnapshot
)
>
1
)
{
array_pop
(
$this
->
_scopeSnapshot
);
memory_get_usage
();
// Memory GC
}
return
$this
;
}
/**
* Saves current configuration snapshot,
* for pussible restoring in feature
*
* @return EcomDev_PHPUnit_Model_Config
*/
public
function
saveScopeSnapshot
()
{
$this
->
_scopeSnapshot
[]
=
clone
$this
->
_xml
;
return
$this
;
}
...
...
app/code/community/EcomDev/PHPUnit/Model/Fixture.php
View file @
e1a9e49c
...
...
@@ -36,9 +36,24 @@ class EcomDev_PHPUnit_Model_Fixture
// Default eav loader class node in loaders configuration
const
DEFAULT_EAV_LOADER_NODE
=
'default'
;
// Default shared fixture name
const
DEFAULT_SHARED_FIXTURE_NAME
=
'default'
;
// Default eav loader class alias
const
DEFAULT_EAV_LOADER_CLASS
=
'ecomdev_phpunit/fixture_eav_default'
;
// Key for storing fixture data into storage
const
STORAGE_KEY_FIXTURE
=
'fixture'
;
// Key for loaded tables into database
const
STORAGE_KEY_TABLES
=
'tables'
;
// Key for loaded entities by EAV loaders
const
STORAGE_KEY_ENTITIES
=
'entities'
;
// Key for created scope models
const
STORAGE_KEY_SCOPE
=
'scope'
;
/**
* Fixtures array, contains config,
* table and eav keys.
...
...
@@ -70,6 +85,20 @@ class EcomDev_PHPUnit_Model_Fixture
*/
protected
$_fixture
=
array
();
/**
* Storage object, for storing data between tests
*
* @var Varien_Object
*/
protected
$_storage
=
null
;
/**
* Scope of the fixture,
* used for different logic depending on
*
* @var string
*/
protected
$_scope
=
self
::
SCOPE_LOCAL
;
/**
* Fixture options
...
...
@@ -78,9 +107,21 @@ class EcomDev_PHPUnit_Model_Fixture
*/
protected
$_options
=
array
();
/**
* List of scope model aliases by scope type
*
* @var array
*/
protected
static
$_scopeModelByType
=
array
(
'store'
=>
'core/store'
,
'group'
=>
'core/store_group'
,
'website'
=>
'core/website'
);
/**
* Associative array of configuration nodes xml that was changed by fixture,
* it is used to preserve
* @deprecated since 0.2.1
*
* @var array
*/
...
...
@@ -89,6 +130,7 @@ class EcomDev_PHPUnit_Model_Fixture
/**
* Hash of current scope instances (store, website, group)
*
* @deprecated since 0.2.1
* @return array
*/
protected
$_currentScope
=
array
();
...
...
@@ -117,7 +159,112 @@ class EcomDev_PHPUnit_Model_Fixture
}
/**
* Loads fixture from test case annotations
* Sets storage for fixutures
*
* @param Varien_Object $storage
* @return EcomDev_PHPUnit_Model_Fixture
*/
public
function
setStorage
(
Varien_Object
$storage
)
{
$this
->
_storage
=
$storage
;
return
$this
;
}
/**
* Retrieve fixture storage
*
* @return Varien_Object
*/
public
function
getStorage
()
{
return
$this
->
_storage
;
}
/**
* Retrieves storage data for a particular fixture scope
*
* @param string $key
* @param string|null $scope
* @return mixed
*/
public
function
getStorageData
(
$key
,
$scope
=
null
)
{
if
(
$scope
===
null
)
{
$scope
=
$this
->
getScope
();
}
$dataKey
=
sprintf
(
'%s_%s'
,
$scope
,
$key
);
return
$this
->
getStorage
()
->
getData
(
$dataKey
);
}
/**
* Sets storage data for a particular fixture scope
*
* @param string $key
* @param mixed $value
* @param string|null $scope
* @return EcomDev_PHPUnit_Model_Fixture
*/
public
function
setStorageData
(
$key
,
$value
,
$scope
=
null
)
{
if
(
$scope
===
null
)
{
$scope
=
$this
->
getScope
();
}
$dataKey
=
sprintf
(
'%s_%s'
,
$scope
,
$key
);
$this
->
getStorage
()
->
setData
(
$dataKey
,
$value
);
return
$this
;
}
/**
* Returns current fixture scope
*
* @return string
*/
public
function
getScope
()
{
return
$this
->
_scope
;
}
/**
* Sets current fixture scope
*
* @param string $scope EcomDev_PHPUnit_Model_Fixture_Interface::SCOPE_LOCAL|EcomDev_PHPUnit_Model_Fixture_Interface::SCOPE_SHARED
* @return EcomDev_PHPUnit_Model_Fixture
*/
public
function
setScope
(
$scope
)
{
$this
->
_scope
=
$scope
;
return
$this
;
}
/**
* Check that current fixture scope is equal to SCOPE_SHARED
*
* @return boolean
*/
public
function
isScopeShared
()
{
return
$this
->
getScope
()
===
self
::
SCOPE_SHARED
;
}
/**
* Check that current fixture scope is equal to SCOPE_LOCAL
*
* @return boolean
*/
public
function
isScopeLocal
()
{
return
$this
->
getScope
()
===
self
::
SCOPE_LOCAL
;
}
/**
* Loads fixture files from test case annotations
*
* @param EcomDev_PHPUnit_Test_Case $testCase
* @return EcomDev_PHPUnit_Model_Fixture
...
...
@@ -129,12 +276,63 @@ class EcomDev_PHPUnit_Model_Fixture
array
(
'class'
,
'method'
)
);
$this
->
_loadFixtureFiles
(
$fixtures
,
$testCase
);
return
$this
;
}
/**
* Loads fixture files from test class annotations
*
* @param string $className
* @return EcomDev_PHPUnit_Model_Fixture
*/
public
function
loadForClass
(
$className
)
{
$reflection
=
EcomDev_Utils_Reflection
::
getRelflection
(
$className
);
$method
=
$reflection
->
getMethod
(
'getAnnotationByNameFromClass'
);
if
(
!
$method
instanceof
ReflectionMethod
)
{
throw
new
RuntimeException
(
'Unable to read class annotations, because it is not extended from EcomDev_PHPUnit_Test_Case'
);
}
$fixtures
=
$method
->
invokeArgs
(
null
,
array
(
$className
,
'loadSharedFixture'
,
'class'
)
);
$this
->
_loadFixtureFiles
(
$fixtures
,
$className
);
return
$this
;
}
/**
* Loads fixture files
*
* @param string $fixtures
* @param string|EcomDev_PHPUnit_Test_Case $classOrInstance
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected
function
_loadFixtureFiles
(
array
$fixtures
,
$classOrInstance
)
{
$isShared
=
(
$this
->
isScopeShared
()
||
!
$classOrInstance
instanceof
EcomDev_PHPUnit_Test_Case
);
foreach
(
$fixtures
as
$fixture
)
{
if
(
empty
(
$fixture
))
{
if
(
empty
(
$fixture
)
&&
$isShared
)
{
$fixture
=
self
::
DEFAULT_SHARED_FIXTURE_NAME
;
}
elseif
(
empty
(
$fixture
))
{
$fixture
=
null
;
}
$filePath
=
$testCase
->
getYamlFilePath
(
'fixtures'
,
$fixture
);
$filePath
=
false
;
if
(
$isShared
)
{
$reflection
=
EcomDev_Utils_Reflection
::
getRelflection
(
$classOrInstance
);
$method
=
$reflection
->
getMethod
(
'getYamlFilePathByClass'
);
if
(
$method
instanceof
ReflectionMethod
)
{
$filePath
=
$method
->
invokeArgs
(
null
,
array
(
$classOrInstance
,
'fixtures'
,
$fixture
));
}
}
else
{
$filePath
=
$classOrInstance
->
getYamlFilePath
(
'fixtures'
,
$fixture
);
}
if
(
!
$filePath
)
{
throw
new
RuntimeException
(
'Unable to load fixture for test'
);
...
...
@@ -173,7 +371,9 @@ class EcomDev_PHPUnit_Model_Fixture
*/
public
function
apply
()
{
$this
->
setStorageData
(
self
::
STORAGE_KEY_FIXTURE
,
$this
->
_fixture
);
$reflection
=
EcomDev_Utils_Reflection
::
getRelflection
(
$this
);
foreach
(
$this
->
_fixture
as
$part
=>
$data
)
{
$method
=
'_apply'
.
uc_words
(
$part
,
''
,
'_'
);
if
(
$reflection
->
hasMethod
(
$method
))
{
...
...
@@ -181,6 +381,8 @@ class EcomDev_PHPUnit_Model_Fixture
}
}
// Clear fixture for getting rid of duoble processing
$this
->
_fixture
=
array
();
return
$this
;
}
...
...
@@ -191,6 +393,14 @@ class EcomDev_PHPUnit_Model_Fixture
*/
public
function
discard
()
{
$fixture
=
$this
->
getStorageData
(
self
::
STORAGE_KEY_FIXTURE
);
if
(
!
is_array
(
$fixture
))
{
$fixture
=
array
();
}
$this
->
_fixture
=
$fixture
;
$this
->
setStorageData
(
self
::
STORAGE_KEY_FIXTURE
,
null
);
$reflection
=
EcomDev_Utils_Reflection
::
getRelflection
(
$this
);
foreach
(
$this
->
_fixture
as
$part
=>
$data
)
{
$method
=
'_discard'
.
uc_words
(
$part
,
''
,
'_'
);
...
...
@@ -213,12 +423,14 @@ class EcomDev_PHPUnit_Model_Fixture
if
(
!
is_array
(
$configuration
))
{
throw
new
InvalidArgumentException
(
'Configuration part should be an associative list'
);
}
Mage
::
getConfig
()
->
loadScopeSnapshot
();
foreach
(
$configuration
as
$path
=>
$value
)
{
$this
->
_setConfigNodeValue
(
$path
,
$value
);
}
Mage
::
getConfig
()
->
loadDb
();
Mage
::
app
()
->
reinitStores
();
return
$this
;
}
...
...
@@ -250,7 +462,6 @@ class EcomDev_PHPUnit_Model_Fixture
throw
new
InvalidArgumentException
(
'Configuration value should be a valid xml string'
);
}
$this
->
_originalConfigurationXml
[
$path
]
=
$node
->
asNiceXml
();
$node
->
extend
(
$xmlElement
,
true
);
}
...
...
@@ -258,15 +469,25 @@ class EcomDev_PHPUnit_Model_Fixture
}
/**
* Re
verts fixture configuration values in Mage_Core_Model_Config
* Re
stores config to a previous configuration scope
*
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected
function
_
discard
Config
()
protected
function
_
restore
Config
()
{
Mage
::
getConfig
()
->
loadScopeSnapshot
();
Mage
::
getConfig
()
->
loadDb
();
Mage
::
app
()
->
reinitStores
();
return
$this
;
}
/**
* Reverts fixture configuration values in Mage_Core_Model_Config
*
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected
function
_discardConfig
()
{
$this
->
_restoreConfig
();
return
$this
;
}
...
...
@@ -277,15 +498,9 @@ class EcomDev_PHPUnit_Model_Fixture
*/
protected
function
_discardConfigXml
()
{
foreach
(
$this
->
_originalConfigurationXml
as
$path
=>
$value
)
{
$node
=
Mage
::
getConfig
()
->
getNode
(
$path
);
$parentNode
=
$node
->
getParent
();
unset
(
$parentNode
->
{
$node
->
getName
()});
$oldXml
=
new
Varien_Simplexml_Element
(
$value
);
$parentNode
->
appendChild
(
$oldXml
);
if
(
!
isset
(
$this
->
_fixture
[
'config'
]))
{
$this
->
_resetConfig
();
}
$this
->
_originalConfigurationXml
=
array
();
return
$this
;
}
...
...
@@ -303,12 +518,24 @@ class EcomDev_PHPUnit_Model_Fixture
);
}
$ignoreCleanUp
=
array
();
// Ignore cleaning of tables if shared fixture loaded something
if
(
$this
->
isScopeLocal
()
&&
$this
->
getStorageData
(
self
::
STORAGE_KEY_TABLES
,
self
::
SCOPE_SHARED
))
{
$ignoreCleanUp
=
array_keys
(
$this
->
getStorageData
(
self
::
STORAGE_KEY_TABLES
,
self
::
SCOPE_SHARED
));
}
foreach
(
$tables
as
$tableEntity
=>
$data
)
{
$this
->
getResource
()
->
cleanTable
(
$tableEntity
);
if
(
!
in_array
(
$tableEntity
,
$ignoreCleanUp
))
{
$this
->
getResource
()
->
cleanTable
(
$tableEntity
);
}
if
(
!
empty
(
$data
))
{
$this
->
getResource
()
->
loadTableData
(
$tableEntity
,
$data
);
}
}
$this
->
setStorageData
(
self
::
STORAGE_KEY_TABLES
,
$tables
);
}
/**
...
...
@@ -325,9 +552,22 @@ class EcomDev_PHPUnit_Model_Fixture
);
}
foreach
(
$tables
as
$tableEntity
=>
$data
)
{
$restoreTableData
=
array
();
// Data for tables used in shared fixture
if
(
$this
->
isScopeLocal
()
&&
$this
->
getStorageData
(
self
::
STORAGE_KEY_TABLES
,
self
::
SCOPE_SHARED
))
{
$restoreTableData
=
$this
->
getStorageData
(
self
::
STORAGE_KEY_TABLES
,
self
::
SCOPE_SHARED
);
}
foreach
(
array_keys
(
$tables
)
as
$tableEntity
)
{
$this
->
getResource
()
->
cleanTable
(
$tableEntity
);
if
(
isset
(
$restoreTableData
[
$tableEntity
]))
{
$this
->
getResource
()
->
loadTableData
(
$tableEntity
,
$restoreTableData
[
$tableEntity
]);
}
}
$this
->
setStorageData
(
self
::
STORAGE_KEY_TABLES
,
null
);
}
/**
...
...
@@ -357,7 +597,7 @@ class EcomDev_PHPUnit_Model_Fixture
EcomDev_Utils_Reflection
::
setRestrictedPropertyValue
(
$website
,
'_configCache'
,
array
()
);
// Should change value
default
:
Mage
::
getConfig
()
->
setNode
(
$path
,
$value
);
...
...
@@ -402,10 +642,13 @@ class EcomDev_PHPUnit_Model_Fixture
foreach
(
$entities
as
$entityType
=>
$values
)
{
$this
->
_getEavLoader
(
$entityType
)
->
setFixture
(
$this
)
->
setOptions
(
$this
->
_options
)
->
loadEntity
(
$entityType
,
$values
);
}
$this
->
setStorageData
(
self
::
STORAGE_KEY_ENTITIES
,
array_keys
(
$entities
));
return
$this
;
}
...
...
@@ -417,7 +660,17 @@ class EcomDev_PHPUnit_Model_Fixture
*/
protected
function
_discardEav
(
$entities
)
{
$ignoreCleanUp
=
array
();
// Ignore cleaning of entities if shared fixture loaded something for them
if
(
$this
->
isScopeLocal
()
&&
$this
->
getStorageData
(
self
::
STORAGE_KEY_ENTITIES
,
self
::
SCOPE_SHARED
))
{
$ignoreCleanUp
=
$this
->
getStorageData
(
self
::
STORAGE_KEY_ENTITIES
,
self
::
SCOPE_SHARED
);
}
foreach
(
array_keys
(
$entities
)
as
$entityType
)
{
if
(
in_array
(
$entityType
,
$ignoreCleanUp
))
{
continue
;
}
$this
->
_getEavLoader
(
$entityType
)
->
cleanEntity
(
$entityType
);
}
...
...
@@ -434,38 +687,99 @@ class EcomDev_PHPUnit_Model_Fixture
*/
protected
function
_applyScope
(
$types
)
{
$modelByType
=
array
(
'store'
=>
'core/store'
,
'group'
=>
'core/store_group'
,
'website'
=>
'core/website'
Mage
::
app
()
->
disableEvents
();
// Validate received fixture data
$this
->
_validateScope
(
$types
);
if
(
$this
->
getStorageData
(
self
::
STORAGE_KEY_SCOPE
)
!==
null
)
{
throw
new
RuntimeException
(
'Scope data was not cleared after previous test'
);
}
$scopeModels
=
array
();
foreach
(
$types
as
$type
=>
$rows
)
{
foreach
(
$rows
as
$row
)
{
$model
=
$this
->
_handleScopeRow
(
$type
,
$row
);
if
(
$model
)
{
$scopeModels
[
$type
][
$model
->
getId
()]
=
$model
;
}
}
}
$this
->
setStorageData
(
self
::
STORAGE_KEY_SCOPE
,
$scopeModels
);
Mage
::
app
()
->
enableEvents
();
Mage
::
app
()
->
reinitStores
();
return
$this
;
}
/**
* Handle scope row data
*
* @param string $type
* @param array $row
* @return boolean|Mage_Core_Model_Abstract
*/
protected
function
_handleScopeRow
(
$type
,
$row
)
{
$previousScope
=
array
();
if
(
$this
->
isScopeLocal
()
&&
$this
->
getStorageData
(
self
::
STORAGE_KEY_SCOPE
,
self
::
SCOPE_SHARED
)
!==
null
)
{
$previousScope
=
$this
->
getStorageData
(
self
::
STORAGE_KEY_SCOPE
,
self
::
SCOPE_SHARED
);
}
if
(
isset
(
$previousScope
[
$type
][
$row
[
$type
.
'_id'
]]))
{
return
false
;
}
$scopeModel
=
Mage
::
getModel
(
self
::
$_scopeModelByType
[
$type
]);
$scopeModel
->
setData
(
$row
);
// Change property for saving new objects with specified ids
EcomDev_Utils_Reflection
::
setRestrictedPropertyValues
(
$scopeModel
->
getResource
(),
array
(
'_useIsObjectNew'
=>
true
,
'_isPkAutoIncrement'
=>
false
)
);
Mage
::
app
()
->
disableEvents
();
$scopeModel
->
isObjectNew
(
true
);
$scopeModel
->
save
();
// Revert changed property
EcomDev_Utils_Reflection
::
setRestrictedPropertyValues
(
$scopeModel
->
getResource
(),
array
(
'_useIsObjectNew'
=>
false
,
'_isPkAutoIncrement'
=>
true
)
);
return
$scopeModel
;
}
/**
* Validate scope data
*
* @param array $types
* @param array $modelByType
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected
function
_validateScope
(
$types
)
{
foreach
(
$types
as
$type
=>
$rows
)
{
if
(
!
isset
(
$m
odelByType
[
$type
]))
{
if
(
!
isset
(
self
::
$_scopeM
odelByType
[
$type
]))
{
throw
new
RuntimeException
(
sprintf
(
'Unknown "%s" scope type specified'
,
$type
));
}
foreach
(
$rows
as
$row
)
{
foreach
(
$rows
as
$row
Number
=>
$row
)
{
$scopeModel
=
Mage
::
getModel
(
$modelByType
[
$type
]);
$this
->
_currentScope
[
$type
][]
=
$scopeModel
;
$scopeModel
->
setData
(
$row
);
// Change property for saving new objects with specified ids
EcomDev_Utils_Reflection
::
setRestrictedPropertyValue
(
$scopeModel
->
getResource
(),
'_useIsObjectNew'
,
true
);
$scopeModel
->
isObjectNew
(
true
);
$scopeModel
->
save
();
// Revert changed property
EcomDev_Utils_Reflection
::
setRestrictedPropertyValue
(
$scopeModel
->
getResource
(),
'_useIsObjectNew'
,
false
);
if
(
!
isset
(
$row
[
$type
.
'_id'
]))
{
throw
new
RuntimeException
(
sprintf
(
'Missing primary key for "%s" scope entity at #%d row'
,
$type
,
$rowNumber
+
1
));
}
}
}
Mage
::
app
()
->
enableEvents
();
Mage
::
app
()
->
reinitStores
();
return
$this
;
}
...
...
@@ -477,19 +791,29 @@ class EcomDev_PHPUnit_Model_Fixture
*/
protected
function
_discardScope
()
{
if
(
$this
->
getStorageData
(
self
::
STORAGE_KEY_SCOPE
)
===
null
)
{
return
$this
;
}
Mage
::
app
()
->
disableEvents
();
$scope
=
array_reverse
(
$this
->
_currentScope
);
$scope
=
array_reverse
(
$this
->
getStorageData
(
self
::
STORAGE_KEY_SCOPE
)
);
foreach
(
$scope
as
$models
)
{
foreach
(
$models
as
$model
)
{
$model
->
delete
();
}
}
$this
->
_currentScope
=
array
();
$this
->
setStorageData
(
self
::
STORAGE_KEY_SCOPE
,
null
);
Mage
::
app
()
->
getCache
()
->
clean
(
Zend_Cache
::
CLEANING_MODE_MATCHING_TAG
,
array
(
Mage_Core_Model_Mysql4_Collection_Abstract
::
CACHE_TAG
)
Zend_Cache
::
CLEANING_MODE_MATCHING_ANY_TAG
,
array
(
Mage_Core_Model_Store
::
CACHE_TAG
,
Mage_Core_Model_Store_Group
::
CACHE_TAG
,
Mage_Core_Model_Website
::
CACHE_TAG
)
);
Mage
::
app
()
->
enableEvents
();
Mage
::
app
()
->
reinitStores
();
return
$this
;
...
...
app/code/community/EcomDev/PHPUnit/Model/Fixture/Interface.php
View file @
e1a9e49c
...
...
@@ -25,6 +25,9 @@
*/
interface
EcomDev_PHPUnit_Model_Fixture_Interface
extends
EcomDev_PHPUnit_Model_Test_Loadable_Interface
{
const
SCOPE_LOCAL
=
'local'
;
const
SCOPE_SHARED
=
'shared'
;
/**
* Sets fixture options
*
...
...
@@ -32,4 +35,74 @@ interface EcomDev_PHPUnit_Model_Fixture_Interface extends EcomDev_PHPUnit_Model_
* @return EcomDev_PHPUnit_Model_Fixture_Interface
*/
public
function
setOptions
(
array
$options
);
/**
* Sets storage for fixutures
*
* @param Varien_Object $storage
* @return EcomDev_PHPUnit_Model_Fixture_Interface
*/
public
function
setStorage
(
Varien_Object
$storage
);
/**
* Retrieve fixture storage
*
* @return Varien_Object
*/
public
function
getStorage
();
/**
* Retrieves storage data for a particular fixture scope
*
* @param string $key
* @param string|null $scope
*/
public
function
getStorageData
(
$key
,
$scope
=
null
);
/**
* Sets storage data for a particular fixture scope
*
* @param string $key
* @param mixed $value
* @param string|null $scope
*/
public
function
setStorageData
(
$key
,
$value
,
$scope
=
null
);
/**
* Returns current fixture scope
*
* @return string
*/
public
function
getScope
();
/**
* Sets current fixture scope
*
*
* @param string $scope EcomDev_PHPUnit_Model_Fixture_Interface::SCOPE_LOCAL|EcomDev_PHPUnit_Model_Fixture_Interface::SCOPE_SHARED
*/
public
function
setScope
(
$scope
);
/**
* Check that current fixture scope is equal to SCOPE_SHARED
*
* @return boolean
*/
public
function
isScopeShared
();
/**
* Check that current fixture scope is equal to SCOPE_LOCAL
*
* @return boolean
*/
public
function
isScopeLocal
();
/**
* Loads fixture files from test class annotations
*
* @param string $className
* @return EcomDev_PHPUnit_Model_Fixture_Interface
*/
public
function
loadForClass
(
$className
);
}
\ No newline at end of file
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture.php
View file @
e1a9e49c
...
...
@@ -58,7 +58,7 @@ class EcomDev_PHPUnit_Model_Mysql4_Fixture extends Mage_Core_Model_Mysql4_Abstra
$records
[]
=
$this
->
_getTableRecord
(
$row
,
$tableColumns
);
}
$this
->
_getWriteAdapter
()
->
insert
Multipl
e
(
$this
->
_getWriteAdapter
()
->
insert
OnDuplicat
e
(
$this
->
getTable
(
$tableEntity
),
$records
);
...
...
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Abstract.php
View file @
e1a9e49c
...
...
@@ -36,6 +36,13 @@ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev
*/
protected
$_options
=
array
();
/**
* Fixture model
*
* @var EcomDev_PHPUnit_Model_Fixture_Interface
*/
protected
$_fixture
=
null
;
/**
* Retrieve required indexers for re-building
*
...
...
@@ -46,6 +53,17 @@ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev
return
$this
->
_requiredIndexers
;
}
/**
* Sets fixture model to EAV loader
*
* @param EcomDev_PHPUnit_Model_Fixture_Interface $fixture
*/
public
function
setFixture
(
$fixture
)
{
$this
->
_fixture
=
$fixture
;
return
$this
;
}
/**
* Set fixture options
*
...
...
@@ -95,8 +113,19 @@ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev
*/
public
function
loadEntity
(
$entityType
,
$values
)
{
$originalRequiredIndexers
=
$this
->
_requiredIndexers
;
if
(
!
empty
(
$this
->
_options
[
'addRequiredIndex'
]))
{
foreach
(
$this
->
_options
[
'addRequiredIndex'
]
as
$data
)
{
if
(
preg_match
(
'/^([a-z0-9_\\-])+\\s+([a-z0-9_\\-])\s*$/i'
,
$data
,
$match
)
&&
$match
[
1
]
==
$entityType
)
{
$this
->
_requiredIndexers
[]
=
$match
[
2
];
}
}
}
$entityTypeModel
=
Mage
::
getSingleton
(
'eav/config'
)
->
getEntityType
(
$entityType
);
$entityTableColumns
=
$this
->
_getWriteAdapter
()
->
describeTable
(
$this
->
getTable
(
$entityTypeModel
->
getEntityTable
())
);
...
...
@@ -197,6 +226,8 @@ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev
}
}
// Restoring original required indexers for making tests isolated
$this
->
_requiredIndexers
=
$originalRequiredIndexers
;
return
$this
;
}
...
...
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Product.php
View file @
e1a9e49c
...
...
@@ -25,7 +25,6 @@ class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Catalog_Product extends EcomDev_P
{
protected
$_requiredIndexers
=
array
(
'cataloginventory_stock'
,
'catalog_product_flat'
,
'catalog_product_attribute'
,
'catalog_product_price'
);
...
...
app/code/community/EcomDev/PHPUnit/Test/Case.php
View file @
e1a9e49c
...
...
@@ -271,12 +271,28 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
* @return array
*/
public
function
getAnnotationByName
(
$name
,
$sources
=
'method'
)
{
return
self
::
getAnnotationByNameFromClass
(
get_class
(
$this
),
$name
,
$sources
,
$this
->
getName
(
false
));
}
/**
* Retrieves annotation by its name from different sources (class, method) based on meta information
*
* @param string $className
* @param string $name annotation name
* @param array|string $sources
* @param string $testName test method name
*/
public
static
function
getAnnotationByNameFromClass
(
$className
,
$name
,
$sources
=
'class'
,
$testName
=
''
)
{
if
(
is_string
(
$sources
))
{
$sources
=
array
(
$sources
);
}
$allAnnotations
=
$this
->
getAnnotations
();
$allAnnotations
=
PHPUnit_Util_Test
::
parseTestMethodAnnotations
(
$className
,
$testName
);
$annotation
=
array
();
// Walkthrough sources for annotation retrieval
...
...
@@ -627,12 +643,30 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
*
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected
function
getFixture
()
protected
static
function
getFixture
()
{
return
Mage
::
getSingleton
(
$this
->
getLoadableClassAlias
(
'fixture'
,
self
::
XML_PATH_DEFAULT_FIXTURE_MODEL
));;
$fixture
=
Mage
::
getSingleton
(
self
::
getLoadableClassAlias
(
'fixture'
,
self
::
XML_PATH_DEFAULT_FIXTURE_MODEL
)
);
if
(
!
$fixture
instanceof
EcomDev_PHPUnit_Model_Fixture_Interface
)
{
throw
new
RuntimeException
(
'Fixture model should implement EcomDev_PHPUnit_Model_Fixture_Interface interface'
);
}
$storage
=
Mage
::
registry
(
EcomDev_PHPUnit_Model_App
::
REGISTRY_PATH_SHARED_STORAGE
);
if
(
!
$storage
instanceof
Varien_Object
)
{
throw
new
RuntimeException
(
'Fixture storage object was not initialized during test application setup'
);
}
$fixture
->
setStorage
(
Mage
::
registry
(
EcomDev_PHPUnit_Model_App
::
REGISTRY_PATH_SHARED_STORAGE
)
);
return
$fixture
;
}
/**
...
...
@@ -642,10 +676,12 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
*/
protected
function
getExpectation
()
{
return
Mage
::
getSingleton
(
$this
->
getLoadableClassAlias
(
'expectation'
,
self
::
XML_PATH_DEFAULT_EXPECTATION_MODEL
));
return
Mage
::
getSingleton
(
self
::
getLoadableClassAlias
(
'expectation'
,
self
::
XML_PATH_DEFAULT_EXPECTATION_MODEL
)
);
}
...
...
@@ -656,14 +692,17 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
* @param string $type
* @param string $configPath
*/
protected
function
getLoadableClassAlias
(
$type
,
$configPath
)
protected
static
function
getLoadableClassAlias
(
$type
,
$configPath
)
{
$annotationValue
=
$this
->
getAnnotationByName
(
$type
.
'Model'
,
'class'
);
$annotationValue
=
self
::
getAnnotationByNameFromClass
(
get_called_class
(),
$type
.
'Model'
);
if
(
current
(
$annotationValue
))
{
$classAlias
=
current
(
$annotationValue
);
}
else
{
$classAlias
=
$this
->
app
()
->
getConfig
()
->
getNode
(
$configPath
);
$classAlias
=
self
::
app
()
->
getConfig
()
->
getNode
(
$configPath
);
}
return
$classAlias
;
...
...
@@ -699,12 +738,25 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
$name
=
$this
->
getName
(
false
);
}
return
self
::
getYamlFilePathByClass
(
get_called_class
(),
$type
,
$name
);
}
/**
* Loads YAML file from directory inside of the unit test class
*
* @param string $className class name for looking fixture files
* @param string $type type of YAML data (fixtures,expectations,dataproviders)
* @param string $name the file name for loading
* @return string|boolean
*/
public
static
function
getYamlFilePathByClass
(
$className
,
$type
,
$name
)
{
if
(
strrpos
(
$name
,
'.yaml'
)
!==
strlen
(
$name
)
-
5
)
{
$name
.=
'.yaml'
;
}
$classFileObject
=
new
SplFileInfo
(
EcomDev_Utils_Reflection
::
getRelflection
(
$
this
)
->
getFileName
()
EcomDev_Utils_Reflection
::
getRelflection
(
$
className
)
->
getFileName
()
);
$filePath
=
$classFileObject
->
getPath
()
.
DS
...
...
@@ -726,15 +778,38 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
*/
protected
function
setUp
()
{
$this
->
getFixture
()
->
loadByTestCase
(
$this
);
self
::
getFixture
()
->
setScope
(
EcomDev_PHPUnit_Model_Fixture_Interface
::
SCOPE_LOCAL
)
->
loadByTestCase
(
$this
);
$annotations
=
$this
->
getAnnotations
();
$this
->
getFixture
()
->
setOptions
(
$annotations
[
'method'
]);
$this
->
getFixture
()
->
apply
();
self
::
getFixture
()
->
setOptions
(
$annotations
[
'method'
])
->
apply
();
$this
->
app
()
->
resetDispatchedEvents
();
parent
::
setUp
();
}
/**
* Initializes test environment for subset of tests
*
*/
public
static
function
setUpBeforeClass
()
{
self
::
getFixture
()
->
setScope
(
EcomDev_PHPUnit_Model_Fixture_Interface
::
SCOPE_SHARED
)
->
loadForClass
(
get_called_class
());
$annotations
=
PHPUnit_Util_Test
::
parseTestMethodAnnotations
(
get_called_class
()
);
self
::
getFixture
()
->
setOptions
(
$annotations
[
'class'
])
->
apply
();
parent
::
setUpBeforeClass
();
}
/**
* Implements default data provider functionality,
* returns array data loaded from Yaml file with the same name as test method
...
...
@@ -796,9 +871,24 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
$this
->
app
()
->
replaceRegistry
(
$registryPath
,
$originalValue
);
}
$this
->
getFixture
()
->
discard
();
// Clear applied fixture
self
::
getFixture
()
->
setScope
(
EcomDev_PHPUnit_Model_Fixture_Interface
::
SCOPE_LOCAL
)
->
discard
();
// Clear applied fixture
parent
::
tearDown
();
}
/**
* Clean up all the shared fixture data
*
* @return void
*/
public
static
function
tearDownAfterClass
()
{
self
::
getFixture
()
->
setScope
(
EcomDev_PHPUnit_Model_Fixture_Interface
::
SCOPE_SHARED
)
->
discard
();
parent
::
tearDownAfterClass
();
}
}
\ No newline at end of file
lib/EcomDev/Utils/Reflection.php
View file @
e1a9e49c
...
...
@@ -44,6 +44,23 @@ class EcomDev_Utils_Reflection
$reflectionProperty
->
setValue
((
is_string
(
$object
)
?
null
:
$object
),
$value
);
}
/**
* Sets multiple restricted property values for an object
*
* @param string|object $object class name
* @param array $properties
*/
public
static
function
setRestrictedPropertyValues
(
$object
,
array
$properties
)
{
if
(
version_compare
(
PHP_VERSION
,
'5.3.0'
,
'<'
))
{
throw
new
RuntimeException
(
'For setting of restricted properties via Reflection, PHP version should be 5.3.0 or later'
);
}
foreach
(
$properties
as
$property
=>
$value
)
{
self
::
setRestrictedPropertyValue
(
$object
,
$property
,
$value
);
}
}
/**
* Gets protected or private property value
*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment