texto - Clases de carga automática PHPUnit
string strip_tags (2)
Pregunta en resumen
¿Cómo puedo hacer que el autocargador encuentre todas las clases requeridas para ejecutar mis pruebas de PHP?
Pregunta en detalle
Quiero cargar automáticamente las clases que estoy usando en PHPUnit en Eclipse. Mi estructura de directorio es la siguiente.
Project (called yii-app)
protected
dirA
classA.php
dirB
classB.php
yii-1.1.14.f0fee9
Yii.php
tests
ClassATest.php
ClassBTest.php
bootstrap.php
Autoloader.php
Uso el bootstrap.php
y el Autoloader.php
que encontré aquí , vea más abajo para más detalles. La Clase classA
no hace uso del framework Yii, y las pruebas en ClassATest
ejecutan sin problemas. La Clase classB
hace uso del framework Yii. Una de las primeras líneas es:
Yii::import(''application.<path into some directory>.*'')
Cuando intento ejecutar las pruebas en ClassBTest.php
, ClassBTest.php
el siguiente error.
Fatal error: Class ''Yii'' not found in /Users/physicalattraction/git/yii-app/protected/dirB/classB.php on line 3
Incluso si registro el directorio completo del proyecto (incluidos los subdirectorios), la Clase Yii
no se encuentra, mientras está ahí. ¿Qué debería cambiar para que estas pruebas se ejecuten también?
Nota
Tengo el mismo problema si intento ejecutar las pruebas directamente desde la terminal, por lo que no está relacionado con Eclipse.
$ ./composer/vendor/bin/phpunit --bootstrap=tests/bootstrap.php tests
PHPUnit 4.5.1 by Sebastian Bergmann and contributors.
Fatal error: Class ''Yii'' not found in /Users/physicalattraction/git/yii-app/protected/dirB/classB.php on line 3
Detalles
Configuración de PHPUnit en Eclipse
bootstrap.php
<?php
include_once(''AutoLoader.php'');
// Register the directory to your include files
Toolbox/Testing/AutoLoader::registerDirectory(__DIR__.''/../yii-1.1.14.f0fee9'');
Toolbox/Testing/AutoLoader::registerDirectory(__DIR__.''/../protected'');
?>
Autoloader.php
<?php
namespace Toolbox/Testing;
/**
* This class is an auto loader for use with vanilla PHP projects'' testing environment. Use it in
* the bootstrap to register classes without having to use a framework (which you can, and should if
* it''s a better solution for you) and without having to use includes everywhere.
*
* It assumes that the file path in relation to the namespace follows the PSR-0 standard.
*
* IMPORTANT NOTE: When just registering directories, the class has no ability to discern
* conflicting class names in different namespaces, which means that classes with the same name will
* override each other! Always use the registerNamespace()-method if possible!
*
* Inspired by Jess Telford''s AutoLoader (http://jes.st/).
*
* @see http://jes.st/2011/phpunit-bootstrap-and-autoloading-classes/
* @see http://petermoulding.com/php/psr
* @see http://www.php-fig.org/psr/psr-0/
*
* @codeCoverageIgnore
*
* @category Toolbox
* @package Testing
*
* @author Helge Söderström <[email protected]>
*/
class AutoLoader {
/**
* An array keeping class names as key and their path as the value for classes registered with
* AutoLoader::registerNamespace().
*
* @var array
*/
protected static $namespaceClassNames = array();
/**
* An array keeping class names as key and their path as the value for classes registered with
* AutoLoader::registerDirectory().
*
* @var array
*/
protected static $directoryClassNames = array();
/**
* Store the filename (sans extension) & full path to all ".php" files found for a namespace.
* The parameter should contain the root namespace as the key and the directory as a value.
*
* @param string $namespace
* @param string $dirName
* @return void
*/
public static function registerNamespace($namespace, $dirName) {
$directoryContents = new /DirectoryIterator($dirName);
foreach($directoryContents as $file) {
if ($file->isDir() && !$file->isLink() && !$file->isDot()) {
$newNamespace = $namespace . "_" . $file->getFileName();
$newDirName = $dirName . "/" . $file->getFilename();
static::registerNamespace($newNamespace, $newDirName);
} elseif (substr($file->getFilename(), -4) === ''.php'') {
$className = substr($file->getFilename(), 0, -4);
$namespacedClassName = $namespace . "_" . $className;
$fileName = realpath($dirName) . "/" . $file->getFilename();
static::$namespaceClassNames[$namespacedClassName] = $fileName;
}
}
}
/**
* Store the filename (sans extension) & full path of all ".php" files found.
*
* NOTE: This method will not be able to differentiate the same class names in different
* namespaces and will therefore overwrite class names if multiple of the same name is
* found. If possible, use registerNamespace instead!
*
* @param string $dirName
* @return void
*/
public static function registerDirectory($dirName) {
$directoryContents = new /DirectoryIterator($dirName);
foreach ($directoryContents as $file) {
if ($file->isDir() && !$file->isLink() && !$file->isDot()) {
// Recurse into directories other than a few special ones.
static::registerDirectory($file->getPathname());
} elseif (substr($file->getFilename(), -4) === ''.php'') {
// Save the class name / path of a .php file found.
$className = substr($file->getFilename(), 0, -4);
AutoLoader::registerClass($className, $file->getPathname());
}
}
}
/**
* Caches a found class with the class name as key and its path as value for use when loading
* on the fly. The class is registered with its class name only, no namespace.
*
* @param string $className
* @param string $fileName
* @return void
*/
public static function registerClass($className, $fileName) {
AutoLoader::$directoryClassNames[$className] = $fileName;
}
/**
* Includes a found class in the runtime environment. Strips namespaces.
*
* @param string $className
* @return void
*/
public static function loadClass($className) {
// First, see if we''ve registered the entire namespace.
$namespacedClassName = str_replace(''//', ''_'', $className);
if (isset(static::$namespaceClassNames[$namespacedClassName])) {
require_once(static::$namespaceClassNames[$namespacedClassName]);
return;
}
// Nope. Have we registered it as a directory?
$psrDirectorySeparators = array(''//', ''_'');
foreach($psrDirectorySeparators as $separator) {
$separatorOccurrence = strrpos($className, $separator);
if($separatorOccurrence !== false) {
$className = substr($className, $separatorOccurrence + 1);
break;
}
}
if (isset(AutoLoader::$directoryClassNames[$className])) {
require_once(AutoLoader::$directoryClassNames[$className]);
}
}
}
// Register our AutoLoad class as the system auto loader.
spl_autoload_register(array(''Toolbox/Testing/AutoLoader'', ''loadClass''));
?>
El autocargador probablemente no encuentre la clase YII. ¿Has intentado agregar?
Toolbox/Testing/AutoLoader::registerDirectory( DIR .''/../yii-1.1.14.f0fee9/framework'');
a su archivo bootstrap.php. Creo que la clase YII está definida en el directorio de framework.
Otra cosa que puedes probar es utilizar el autocargador del compositor.
PD Es una buena práctica duplicar la estructura de su directorio / archivo de la aplicación en el directorio de pruebas. En su caso, ClassATest.php y ClassBTest.php deberían separarse en sus propios directorios de la misma manera que están separados en el directorio protegido.
Descubrí que con los siguientes cambios, funcionó.
Tener la siguiente estructura de directorio
project
protected
config
main.php
test.php
controllers
models
tests
fixtures
functional
report
unit
bootstrap.php
phpunit.xml
En main.php
: agrega los directorios en los que Yii busca clases. Subdirectorios no son buscados automáticamente por Yii, por lo que debe especificar cada directorio individualmente aquí.
// autoloading model and component classes
''import'' => array(
''application.models.*'',
''application.models.support.*'',
''application.components.*'',
....
Defina la siguiente configuración de prueba en test.php
.
<?php
return CMap::mergeArray(
require(dirname(__FILE__).''/main.php''),
array(
''components''=>array(
''fixture''=>array(
''class''=>''system.test.CDbFixtureManager'',
),
''db''=>array(
''class'' => ''CDbConnection'',
''connectionString'' => ''CONNECTIONSTRING'',
''emulatePrepare'' => true,
''username'' => ''USERNAME'',
''password'' => ''PASSWORD'',
''charset'' => ''utf8'',
),
),
)
);
?>
Luego, en el archivo bootstrap, solo use el autocargador Yii.
<?php
$yiit=__DIR__.''/../../yii-1.1.14.f0fee9/yiit.php'';
$config=dirname(__FILE__).''/../config/test.php'';
require_once($yiit);
// Include the following line if you want to write a WebTestCase
// require_once(dirname(__FILE__).''/WebTestCase.php'');
Yii::createWebApplication($config);
?>
Mi caso de prueba necesita un modelo de tipo Order, que está conectado a los orders
una tabla de base de datos. Defina un accesorio en los fixtures/Order.php
directorio fixtures/Order.php
.
<?php
return array(
''order1'' => array(
''id'' => 1011,
''order_number'' => ''on_101''
)
);
?>
Haga el caso de prueba como se indica en los sitios web de Yii y PHPUnit.
class MyExportTest extends CDbTestCase
{
public $fixtures = array(
''orders'' => ''Order''
);
public function test_order()
{
$order = $this->orders(''order1'');
$this->assertTrue($order instanceof Order);
$r = $order->order_number;
$e = "on_101";
$this->assertEquals($r, $e,
sprintf("Received order_number: /n%s/nExpected order_number: /n%s/n", $r, $e));
}
public function test_export()
{
$sut = new MyExport($tenantId, $userGroupId);
$r = $sut->method_to_test()
$e = "expected result";
$this->assertEquals($r, $e,
sprintf("Received result: /n%s/nExpected result: /n%s/n", $r, $e));
}
}