Commit 2cde68ad authored by Ivan Chepurnyi's avatar Ivan Chepurnyi

! Initial refactoring of PHPUnit module started to make fixtures and...

! Initial refactoring of PHPUnit module started to make fixtures and expectations re-usable from other kind of test cases, not only EcomDev_PHPUnit_Test_Case
parent 5b0db121
<?php
require 'app/Mage.php';
if (version_compare(PHP_VERSION, '5.3', '<')) {
exit('Magento Unit Tests can be runned only on PHP version over 5.3');
}
if (!Mage::isInstalled()) {
exit('Magento Unit Tests can be runned only on installed version');
}
/* Replace server variables for proper file naming */
$_SERVER['SCRIPT_NAME'] = dirname(__FILE__) . DS . 'index.php';
$_SERVER['SCRIPT_FILENAME'] = dirname(__FILE__) . DS . 'index.php';
Mage::app('admin');
Mage::getConfig()->init();
/* @depracated since 0.3.0 */
require_once 'app/code/community/EcomDev/PHPUnit/Test/bootstrap.php';
class UnitTests extends EcomDev_PHPUnit_Test_Suite
{
......
......@@ -110,6 +110,13 @@ class EcomDev_PHPUnit_Model_Fixture
*/
protected $_options = array();
/**
* vfsStream wrapper instance
*
* @var EcomDev_PHPUnit_Model_Fixture_Vfs
*/
protected $_vfs = null;
/**
* List of scope model aliases by scope type
*
......@@ -147,6 +154,8 @@ class EcomDev_PHPUnit_Model_Fixture
protected function _construct()
{
$this->_init('ecomdev_phpunit/fixture');
// Additional property for test data fixture
$this->setTestData(new Varien_Object());
}
/**
......@@ -582,7 +591,7 @@ class EcomDev_PHPUnit_Model_Fixture
protected function _discardConfigXml()
{
if (!isset($this->_fixture['config'])) {
$this->_resetConfig();
$this->_restoreConfig();
}
return $this;
}
......@@ -884,4 +893,69 @@ class EcomDev_PHPUnit_Model_Fixture
return $this;
}
/**
* Returns VFS wrapper instance
*
* @return EcomDev_PHPUnit_Model_Fixture_Vfs
* @throws PHPUnit_Framework_SkippedTestError
*/
public function getVfs()
{
if ($this->_vfs !== null) {
return $this->_vfs;
}
if (is_dir(Mage::getBaseDir('lib') . DS . 'vfsStream' . DS . 'main')) {
spl_autoload_register(array($this, 'vfsAutoload'), true, true);
$this->_vfs = Mage::getModel('ecomdev_phpunit/fixture_vfs');
return $this->_vfs;
}
throw new PHPUnit_Framework_SkippedTestError(
'The test was skipped, since vfsStream component is not installed. '
. 'Try install submodules required for this functionality'
);
}
/**
* Autoloader for vfs
*
* @param string $className
* @return bool
*/
public function vfsAutoload($className)
{
if (strpos($className, 'org\\bovigo\\vfs') !== 0) {
return false;
}
$fileName = 'vfsStream' . DS . 'src'
. DS . 'main' . DS . 'php' . DS
. strtr(trim($className, '\\'), '\\', DS) . '.php';
return include $fileName;
}
/**
* Applies VFS structure fixture
*
* @param array $data
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected function _applyVfs($data)
{
$this->getVfs()->apply($data, $this->isScopeLocal());
return $this;
}
/**
* Discards VFS structure fixture
*
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected function _discardVfs()
{
$this->getVfs()->discard();
return $this;
}
}
......@@ -105,4 +105,11 @@ interface EcomDev_PHPUnit_Model_Fixture_Interface extends EcomDev_PHPUnit_Model_
* @return EcomDev_PHPUnit_Model_Fixture_Interface
*/
public function loadForClass($className);
/**
* Returns VFS wrapper instance
*
* @return EcomDev_PHPUnit_Model_Fixture_Vfs
*/
public function getVfs();
}
......@@ -28,8 +28,14 @@ require_once 'Spyc/spyc.php';
abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
{
const XML_PATH_DEFAULT_FIXTURE_MODEL = 'phpunit/suite/fixture/model';
const XML_PATH_DEFAULT_EXPECTATION_MODEL = 'phpunit/suite/expectation/model';
/**
* @deprecated since 0.3.0
**/
const XML_PATH_DEFAULT_FIXTURE_MODEL = EcomDev_PHPUnit_Test_Case_Util::XML_PATH_DEFAULT_FIXTURE_MODEL;
/**
* @deprecated since 0.3.0
**/
const XML_PATH_DEFAULT_EXPECTATION_MODEL = EcomDev_PHPUnit_Test_Case_Util::XML_PATH_DEFAULT_EXPECTATION_MODEL;
/**
......@@ -63,7 +69,7 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
*/
public static function app()
{
return Mage::app();
return EcomDev_PHPUnit_Test_Case_Util::app();
}
/**
......@@ -252,10 +258,11 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
*
* @return string
* @throws RuntimeException if module name was not found for the passed class name
* @deprecated since 0.3.0
*/
public function getModuleName()
{
return $this->app()->getModuleNameByClassName($this);
return EcomDev_PHPUnit_Test_Case_Util::getModuleName($this);
}
/**
......@@ -266,14 +273,7 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
*/
protected static function getModuleNameFromCallStack()
{
$backTrace = debug_backtrace(true);
foreach ($backTrace as $call) {
if (isset($call['object']) && $call['object'] instanceof EcomDev_PHPUnit_Test_Case) {
return $call['object']->getModuleName();
}
}
throw new RuntimeException('Unable to retrieve module name from call stack, because assertion is not called from EcomDev_PHPUnit_Test_Case based class method');
return EcomDev_PHPUnit_Test_Case_Util::getModuleNameFromCallStack();
}
......@@ -284,10 +284,11 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
* @param string $name
* @param array|string $sources
* @return array
* @deprecated since 0.3.0
*/
public function getAnnotationByName($name, $sources = 'method')
{
return self::getAnnotationByNameFromClass(get_class($this), $name, $sources, $this->getName(false));
return EcomDev_PHPUnit_Test_Case_Util::getAnnotationByNameFromClass(get_class($this), $name, $sources, $this->getName(false));
}
/**
......@@ -297,30 +298,12 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
* @param string $name annotation name
* @param array|string $sources
* @param string $testName test method name
* @return array
* @deprecated since 0.3.0
*/
public static function getAnnotationByNameFromClass($className, $name, $sources = 'class', $testName = '')
{
if (is_string($sources)) {
$sources = array($sources);
}
$allAnnotations = PHPUnit_Util_Test::parseTestMethodAnnotations(
$className, $testName
);
$annotation = array();
// Walkthrough sources for annotation retrieval
foreach ($sources as $source) {
if (isset($allAnnotations[$source][$name])) {
$annotation = array_merge(
$allAnnotations[$source][$name],
$annotation
);
}
}
return $annotation;
return EcomDev_PHPUnit_Test_Case_Util::getAnnotationByNameFromClass($className, $name, $sources, $testName);
}
/**
......@@ -691,12 +674,7 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
*/
protected function getExpectation()
{
return Mage::getSingleton(
self::getLoadableClassAlias(
'expectation',
self::XML_PATH_DEFAULT_EXPECTATION_MODEL
)
);
return EcomDev_PHPUnit_Test_Case_Util::getExpectation(get_class($this));
}
......@@ -707,21 +685,11 @@ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
* @param string $type
* @param string $configPath
* @return string
* @deprecated since 0.3.0
*/
protected static function getLoadableClassAlias($type, $configPath)
{
$annotationValue = self::getAnnotationByNameFromClass(
get_called_class(),
$type .'Model'
);
if (current($annotationValue)) {
$classAlias = current($annotationValue);
} else {
$classAlias = (string) self::app()->getConfig()->getNode($configPath);
}
return $classAlias;
return EcomDev_PHPUnit_Test_Case::getLoadableClassAlias(get_called_class(), $type, $configPath);
}
/**
......
<?php
class EcomDev_PHPUnit_Test_Case_Util
{
const XML_PATH_DEFAULT_FIXTURE_MODEL = 'phpunit/suite/fixture/model';
const XML_PATH_DEFAULT_EXPECTATION_MODEL = 'phpunit/suite/expectation/model';
/**
* Returns app for test case, created for type hinting
* in the test case code
*
* @return EcomDev_PHPUnit_Model_App
*/
public static function app()
{
return Mage::app();
}
/**
* Retrieves the module name for current test case
*
* @param PHPUnit_Framework_TestCase $testCase
* @return string
* @throws RuntimeException if module name was not found for the passed class name
*/
public static function getModuleName(PHPUnit_Framework_TestCase $testCase)
{
return self::app()->getModuleNameByClassName($testCase);
}
/**
* Retrieves module name from call stack objects
*
* @return string
* @throws RuntimeException if assertion is called in not from EcomDev_PHPUnit_Test_Case
*/
public static function getModuleNameFromCallStack()
{
$backTrace = debug_backtrace(true);
foreach ($backTrace as $call) {
if (isset($call['object']) && $call['object'] instanceof PHPUnit_Framework_TestCase) {
return self::getModuleName($call['object']);
}
}
throw new RuntimeException('Unable to retrieve module name from call stack, because assertion is not called from EcomDev_PHPUnit_Test_Case based class method');
}
/**
* 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
* @return array
*/
public static function getAnnotationByNameFromClass($className, $name, $sources = 'class', $testName = '')
{
if (is_string($sources)) {
$sources = array($sources);
}
$allAnnotations = PHPUnit_Util_Test::parseTestMethodAnnotations(
$className, $testName
);
$annotation = array();
// Walk-through sources for annotation retrieval
foreach ($sources as $source) {
if (isset($allAnnotations[$source][$name])) {
$annotation = array_merge(
$allAnnotations[$source][$name],
$annotation
);
}
}
return $annotation;
}
/**
* Retrieves loadable class alias from annotation or configuration node
* E.g. class alias for fixture model can be specified via @fixtureModel annotation
*
* @param string $className
* @param string $type
* @param string $configPath
* @return string
*/
protected static function getLoadableClassAlias($className, $type, $configPath)
{
$annotationValue = self::getAnnotationByNameFromClass(
$className,
$type .'Model'
);
if (current($annotationValue)) {
$classAlias = current($annotationValue);
} else {
$classAlias = (string) self::app()->getConfig()->getNode($configPath);
}
return $classAlias;
}
/**
* Returns expectation model singleton
*
* @param string $testCaseClassName
* @return EcomDev_PHPUnit_Model_Expectation
*/
public static function getExpectation($testCaseClassName)
{
return Mage::getSingleton(
self::getLoadableClassAlias(
$testCaseClassName,
'expectation',
self::XML_PATH_DEFAULT_EXPECTATION_MODEL
)
);
}
/**
*
* @param PHPUnit_Framework_TestCase $testCase
*
*/
public static function loadExpectation(PHPUnit_Framework_TestCase $testCase)
{
}
/**
* Retrieves fixture model singleton
*
* @param string $testCaseClassName
* @return EcomDev_PHPUnit_Model_Fixture
* @throws RuntimeException
*/
public static function getFixture($testCaseClassName)
{
$fixture = Mage::getSingleton(
self::getLoadableClassAlias(
$testCaseClassName,
'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;
}
}
\ No newline at end of file
<?php
class EcomDev_PHPUnit_Test_Listener implements PHPUnit_Framework_TestListener
{
const XML_PATH_UNIT_TEST_APP = 'phpunit/suite/app/class';
/**
* First level test suite that is used
* for running all the tests
*
* @var PHPUnit_Framework_TestSuite
*/
protected $firstLevelTestSuite = null;
/**
* Returns app reflection instance
*
* @return ReflectionClass|ReflectionObject
*/
protected function getAppReflection()
{
$appClass = (string) Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_APP);
$reflectionClass = EcomDev_Utils_Reflection::getRelflection($appClass);
return $reflectionClass;
}
/**
* A test suite started.
*
* @param PHPUnit_Framework_TestSuite $suite
*/
public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
if ($this->firstLevelTestSuite === null) {
// Apply app substitution for tests
if ($this->getAppReflection()->hasMethod('applyTestScope')) {
$this->getAppReflection()->getMethod('applyTestScope')->invoke(null);
}
$this->firstLevelTestSuite = $suite;
}
if (EcomDev_Utils_Reflection::getRestrictedPropertyValue($suite, 'testCase')) {
}
}
/**
* A test suite ended.
*
* @param PHPUnit_Framework_TestSuite $suite
*/
public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
if ($this->firstLevelTestSuite === $suite) {
$this->firstLevelTestSuite = null;
// Discard test scope app
if ($this->getAppReflection()->hasMethod('discardTestScope')) {
$this->getAppReflection()->getMethod('discardTestScope')->invoke(null);
}
}
}
/**
* A test started.
*
* @param PHPUnit_Framework_Test $test
*/
public function startTest(PHPUnit_Framework_Test $test)
{
// No action is required for now
}
/**
* A test ended.
*
* @param PHPUnit_Framework_Test $test
* @param float $time
*/
public function endTest(PHPUnit_Framework_Test $test, $time)
{
// No action is required for now
}
/**
* An error occurred.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
// No action is required
}
/**
* A failure occurred.
*
* @param PHPUnit_Framework_Test $test
* @param PHPUnit_Framework_AssertionFailedError $e
* @param float $time
*/
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
// No action is required
}
/**
* Incomplete test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
// No action is required
}
/**
* Skipped test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*
* @since Method available since Release 3.0.0
*/
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
// No action is required
}
}
\ No newline at end of file
......@@ -38,15 +38,11 @@ class EcomDev_PHPUnit_Test_Suite extends PHPUnit_Framework_TestSuite
* Setting up test scope for Magento
* (non-PHPdoc)
* @see PHPUnit_Framework_TestSuite::setUp()
* @deprecated since 0.3.0
*/
protected function setUp()
{
$appClass = (string) Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_APP);
$reflectionClass = EcomDev_Utils_Reflection::getRelflection($appClass);
if ($reflectionClass->hasMethod('applyTestScope')) {
$reflectionClass->getMethod('applyTestScope')->invoke(null);
}
}
/**
......@@ -56,12 +52,7 @@ class EcomDev_PHPUnit_Test_Suite extends PHPUnit_Framework_TestSuite
*/
protected function tearDown()
{
$appClass = (string) Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_APP);
$reflectionClass = EcomDev_Utils_Reflection::getRelflection($appClass);
if ($reflectionClass->hasMethod('discardTestScope')) {
$reflectionClass->getMethod('discardTestScope')->invoke(null);
}
}
/**
......
<?php
if (version_compare(PHP_VERSION, '5.3', '<')) {
exit('Magento Unit Tests can run only on PHP version higher then 5.3');
}
$fileDir = dirname(__FILE__);
// Include Mage file by detecting app root
require_once substr($fileDir, 0, strpos($fileDir, 'app' . DIRECTORY_SEPARATOR)) . 'app/Mage.php';
if (!Mage::isInstalled()) {
exit('Magento Unit Tests can run only on installed version');
}
/* Replace server variables for proper file naming */
$_SERVER['SCRIPT_NAME'] = dirname(__FILE__) . DS . 'index.php';
$_SERVER['SCRIPT_FILENAME'] = dirname(__FILE__) . DS . 'index.php';
Mage::app('admin');
Mage::getConfig()->init();
......@@ -5,17 +5,13 @@ app/code/community/EcomDev/PHPUnit app/code/community/EcomDev/PHPUnit
lib/EcomDev/PHPUnit lib/EcomDev/PHPUnit
lib/EcomDev/Utils lib/EcomDev/Utils
lib/Spyc lib/Spyc
lib/vfsStream lib/vfsStream
shell/ecomdev-phpunit-install.php shell/ecomdev-phpunit-install.php
# Copy local.xml.phpunit if it doesn't already exist
@shell \
LOCALXML=app/etc/local.xml.phpunit; \
if [ ! -f $PROJECT/$LOCALXML ]; then \
cp $MODULE/$LOCALXML $PROJECT/$LOCALXML; \
fi
DIR_BEFORE_INSTALL=`pwd` \
cd $PROJECT/shell \
php -f ecomdev-phpunit-install.php --module $MODULE --project $PROJECT \
cd $DIR_BEFORE_INSTALL
# Copy phpunit.xml if it doesn't already exist
@shell \
PHPUNITXML=phpunit.xml.dist; \
if [ ! -f $PROJECT/$LOCALXML ]; then \
cp $MODULE/$PHPUNITXML $PROJECT/$PHPUNITXML; \
fi
......@@ -10,12 +10,10 @@
stopOnIncomplete="false"
stopOnSkipped="false"
strict="false"
verbose="false">
<testsuites>
<testsuite name="Magento Unit Tests">
<file>UnitTests.php</file>
</testsuite>
</testsuites>
verbose="false"
bootstrap="app/code/community/EcomDev/PHPUnit/Test/bootstrap.php"
loader=""
>
<filter>
<blacklist>
<!-- Exclude Magento Core files from code coverage -->
......
<?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) 2012 EcomDev BV (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>
*/
require_once 'abstract.php';
/**
* Shell script for autoinstalling of required files for phpunit extension
*
*
*/
class EcomDev_PHPUnit_Install extends Mage_Shell_Abstract
{
const FILE_LOCAL_XML = 'app/etc/local.xml.phpunit';
const FILE_PHPUNIT_XML = 'phpunit.xml.dist';
const OLD_FILE_MATCH = '/\\<file\\>UnitTests.php\\<\\/file\\>/';
/**
* This script doesn't need initialization of Magento
*
* @var bool
*/
protected $_includeMage = false;
/**
* Runs scripts itself
*/
public function run()
{
if (!$this->getArg('module') || !$this->getArg('project')) {
die($this->usageHelp());
}
$this->_copyLocalXml();
$this->_copyPHPUnitXml();
}
/**
* Copies local XML file from phpunit extension folder
*
*/
protected function _copyLocalXml()
{
if (!file_exists($this->getArg('project') . DIRECTORY_SEPARATOR . self::FILE_LOCAL_XML)) {
copy($this->getArg('module') . DIRECTORY_SEPARATOR . self::FILE_LOCAL_XML,
$this->getArg('project') . DIRECTORY_SEPARATOR . self::FILE_PHPUNIT_XML);
}
}
/**
* Checks existence of phpunit.xml.dist file, if file is outdated,
* it just replaces the content of it.
*
*/
protected function _copyPHPUnitXml()
{
if (!file_exists($this->getArg('project') . DIRECTORY_SEPARATOR . self::FILE_PHPUNIT_XML)
|| preg_match(self::OLD_FILE_MATCH,
file_get_contents($this->getArg('project') . DIRECTORY_SEPARATOR . self::FILE_PHPUNIT_XML))) {
copy($this->getArg('module') . DIRECTORY_SEPARATOR . self::FILE_PHPUNIT_XML,
$this->getArg('project') . DIRECTORY_SEPARATOR . self::FILE_PHPUNIT_XML);
}
}
}
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