What I am trying to do is to get instance of Doctrine EM (using Bisna Library to load it) in unit test. I can get the instance in controller/model when it's running in 'normal' (not unit testing) mode. And I am going insane of comparing line-by-line code with project where it works :(
Unit test:
<?php
class Application_Models_UserTest extends PHPUNit_Framework_TestCase
{
protected $_em;
protected $_model;
public function setUp()
{
$this->bootstrap = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
$this->_em = Zend_Registry::get('doctrine')->getEntityManager();
$this->_model = new Application_Model_User();
parent::setUp();
//$this->_em = Zend_Registry::get('doctrine')->getEntityManager();
//$this->_model = new Application_Model_User();
}
I get:
1) Application_Models_UserTest::testGetByEmailExists
Zend_Exception: No entry is registered for key 'doctrine'
/var/www/html/social_test/library/vendor/Zend/Registry.php:147
/var/www/html/social_test/tests/application/models/UserTest.php:10
As you can see from commented lines, I tried (being desperate) to get doctrine EM instance after parent::setUp() call, unsuccessfully. Thought that parent::setUp() finishes initializing app and it might help.
I am running it with phpunit -c phpunit.xml. phpunit.xml:
<phpunit bootstrap="./bootstrap.php">
<testsuite name="Application Test Suite">
<directory>./application</directory>
</testsuite>
<testsuite name="Library Test Suite">
<directory>./library</directory>
</testsuite>
<filter>
<whitelist>
<directory suffix=".php">../../library</directory>
</whitelist>
</filter>
<logging>
<log type="coverage-html" target="./public/report" charset="UTF-8"
yui="true" highlight = "true" lowUpperBound="50" highLowerBound="80" />
</logging>
</phpunit>
Unit testing bootstrap.php is also standard and untouched. Plugin path is specified in application.ini and it's in production section (so it's inherited in testing section).
ZF version 1.11.11.
This works for me (taken from ZendCast Many-to-Many with Doctrine 2)
class ModelTestCase
extends PHPUnit_Framework_TestCase
{
/**
*
* #var \Bisna\Application\Container\DoctrineContainer
*/
protected $doctrineContainer;
public function setUp()
{
global $application;
$application->bootstrap();
$this->doctrineContainer = Zend_Registry::get('doctrine');
$em = $this->doctrineContainer->getEntityManager();
$tool = new \Doctrine\ORM\Tools\SchemaTool($em);
$tool->dropDatabase();
$tool->createSchema($em->getMetadataFactory()->getAllMetadata());
parent::setUp();
}
Bootstrap.php for the unit tests looks like this:
<?php
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../../application'));
// Define application environment
define('APPLICATION_ENV', 'testing');
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path()
)));
/** Zend_Application */
require_once 'Zend/Application.php';
require_once 'ModelTestCase.php';
require_once 'ControllerTestCase.php';
// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
//$application->bootstrap();
clearstatcache();
Related
I'm using Zend Framework 1.12. I know it's too old and that's why not finding much support so putting this question here.
I have CronController and I'm calling it through curl request and its not a good approach. As the name specifies, I want to call its functions through the command-line. Please suggest how can I achieve this.
I have tried implementing https://docs.zendframework.com/zend-console/intro/ but it didn't help much.
Thanks in advance.
I assume that CronController is class extending Zend_Controller_Action like this:
class CronController extends Zend_Controller_Action
{
public function processAction()
{
// some very important logic
}
}
If so, don't use this in your CLI calls. Zend_Controller_Action should be used rather with HTTP requests, not CLI calls.
Move your business logic from this controller to separate classes, i.e.:
class My_Logic
{
public function process($options)
{
// some very important logic
}
}
Then, following DRY principle, create instance of this class in your controller:
class CronController extends Zend_Controller_Action
{
public function processAction()
{
$logic = new My_Logic();
$logic->process();
}
}
Now, create bin directory in root path of your project and put there your CLI script (i.e. cron.php):
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
$optsConfig = array(
'app_env=s' => 'Application environment name',
);
$opts = new Zend_Console_Getopt($optsConfig);
$opts->setOptions(
array(
'ignoreCase' => true,
'dashDash' => false,
)
);
$opts->parse();
defined('APPLICATION_ENV') || define('APPLICATION_ENV', $opts->app_env);
/** Zend_Application */
require_once 'Zend/Application.php';
// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
$application->getBootstrap()->bootstrap();
class CronCli
{
public function doProcessing()
{
$logic = new My_Logic();
// here's your logic, the same as in controller
$logic->process();
}
}
$cmd = new CronCli($opts);
$cmd->doProcessing();
Now, you can call this script in your project's main directory:
php bin/cron.php --app_env production
production is your APP_ENV value name from application/configs/application.ini
I'm trying to test a controller. Zend Tool has generated the following code:
class Default_CarrinhoControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
public function setUp()
{
$this->bootstrap = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
parent::setUp();
}
public function testIndexAction()
{
$params = array('action' => 'index', 'controller' => 'Carrinho', 'module' => 'default');
$urlParams = $this->urlizeOptions($params);
$url = $this->url($urlParams);
$this->dispatch($url);
// assertions
$this->assertModule($urlParams['module']);
$this->assertController($urlParams['controller']);
$this->assertAction($urlParams['action']);
$this->assertQueryContentContains(
'div#view-content p',
'View script for controller <b>' . $params['controller'] . '</b> and script/action name <b>' . $params['action'] . '</b>'
);
}
}
PHPUnit Bootstrap
<?php
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
But it has failed and route is correct
Default_CarrinhoControllerTest::testIndexAction()
Zend_Controller_Router_Exception: Route default is not defined
C:\xampp\ZendFramework-1.11.11\library\Zend\Controller\Router\Rewrite.php:318
C:\xampp\ZendFramework-1.11.11\library\Zend\Controller\Router\Rewrite.php:469
C:\xampp\ZendFramework-1.11.11\library\Zend\Test\PHPUnit\ControllerTestCase.php:1180
C:\htdocs\farmaciaonline\FarmaciaOnlineWeb\tests\application\modules\default\controllers\CarrinhoControllerTest.php:16
C:\xampp\php\PEAR\PHPUnit\Framework\TestCase.php:939
C:\xampp\php\PEAR\PHPUnit\Framework\TestCase.php:801
C:\xampp\php\PEAR\PHPUnit\Framework\TestResult.php:649
C:\xampp\php\PEAR\PHPUnit\Framework\TestCase.php:748
C:\xampp\php\PEAR\PHPUnit\Framework\TestSuite.php:772
C:\xampp\php\PEAR\PHPUnit\Framework\TestSuite.php:745
C:\xampp\php\PEAR\PHPUnit\Framework\TestSuite.php:705
C:\xampp\php\PEAR\PHPUnit\TextUI\TestRunner.php:325
C:\xampp\php\PEAR\PHPUnit\TextUI\Command.php:187
C:\xampp\php\PEAR\PHPUnit\TextUI\Command.php:125
C:\xampp\php\phpunit:44
I have the default phpunit generated bootstrap by zend tool, I've setted up some custom routes but the default routes are still working on the application. What could be wrong?
Looks like there's an issue with the the Controller Test Case not setting the default route, if custom routes have been set (this is a different behavior than the framework).
The patch from the issue:
/**
* URL Helper
*
* #param array $urlOptions
* #param string $name
* #param bool $reset
* #param bool $encode
*/
public function url($urlOptions = array(), $name = null, $reset = false, $encode = true, $default = false)
{
$frontController = $this->getFrontController();
$router = $frontController->getRouter();
if (!$router instanceof Zend_Controller_Router_Rewrite) {
throw new Exception('This url helper utility function only works when the router is of type Zend_Controller_Router_Rewrite');
}
if ($default) {
$router->addDefaultRoutes();
}
return $router->assemble($urlOptions, $name, $reset, $encode);
}
You'll need to pass true as the last argument when using the url() function.
Instead of patching the Test Case, you can just add the default routes someplace in the bootstrap process:
$frontController->getRouter()->addDefaultRoutes();
This sounds like a typical problem you have not configured your app in the bootstrap properly and then invoking a request which leads to an undefined route. In your case the route is specified as Route default.
The route might be correct but just undefined.
For debugging purposes, output the $url you invoke so you see what's going on.
I am hardly struggling against problem I experience for last two days.
In fact I can not run test properly and receive:
PHP Fatal error: Call to undefined function Zend_Application() in
C:\xxxxxx\tests\application\controllers\IndexControllerTest.php on
line 10
IndexControllerTest is very simple and looks like this:
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
public function setUp()
{
$this->bootstrap = Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
parent::setUp();
}
public function appBootstrap() {
$this->application = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
$this->application->bootstrap();
}
...
On the other hand bootstrap for tests contains only following code:
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application')); // /../application
// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
Could you please help me with finding a problem? I would like to increase quality of mini project i indend to start but without testing it won't be possible.
Thank you in advance.
I added directories structure for my project. I keep zend libs in Source Files/library/Zend.
The error is coming from this:
$this->bootstrap = Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
You're missing a new before Zend_Application.
But, it's not clear to me what you have the appBootstrap function for unless you're going to use it:
public function setUp()
{
$this->appBootstrap();
parent::setUp();
}
What command are you using to run the tests?
If you don't load the bootstrap you'll get this error.
phpunit --bootstrap tests/bootstrap.php tests
I followed the steps in the following article in order to integrate Zend Framework 1.11 and Doctrine 2:
http://jeboy25.blogspot.com/2010/08/doctrine-2-and-zend-framework-110.html
And I have 3 questions about the article:
1-In the "SchemaToolClass" section i don't understand why the author includes schema_tool.php at the bottom of ZendProject/public/index.php file after :
$application->bootstrap()
->run();
2-when i execute the command "php doctrine orm:schema-tool:create" i have the following error message in the command line:
HP Stack trace:
PHP 1. {main}() /Library/WebServer/Documents/carlending/application/tools/doctrine:0
PHP 2. include() /Library/WebServer/Documents/carlending/application/tools/doctrine:7
PHP 3. require() /Library/WebServer/Documents/carlending/application/tools/doctrine.php:41
PHP 4. Doctrine\Common\ClassLoader->loadClass($className = uninitialized)
the error occurs in the cli-config.php file at the line '$config = new \Doctrine\ORM\Configuration();'
3-Can you explain why the author puts the doctrine generated proxies and models inside the domain folder. Isn't it better that they reside in the models folder like any other model class.
Sometimes i also see some programmers using a 'generated' folder inside models.
If you managed to make a working integration of Zend 1.x and Doctrine i would be very happy if you could also send me a working project that would very helpful.
Thanks for your help.
After reading "Obtaining the EntityManager" section in http://www.doctrine-project.org/docs/orm/2.1/en/tutorials/getting-started-xml-edition.html
I think you need the following three lines to bootstrap:
use Doctrine\ORM\Tools\Setup;
require_once 'Doctrine/ORM/Tools/Setup.php';
Setup::registerAutoloadPEAR();
I've got it to work a few weeks ago, here's my code. Doctrine 2 is really nice :)
In my bootstrap
/**
* Initialize auto loader of Doctrine
*
* #return Doctrine_Manager
*/
protected function _initDoctrine() {
$this->bootstrap('autoload');
require_once('Doctrine/Common/ClassLoader.php');
// Create the doctrine autoloader and remove it from the spl autoload stack (it adds itself)
require_once 'Doctrine/Common/ClassLoader.php';
$doctrineAutoloader = array(new \Doctrine\Common\ClassLoader(), 'loadClass');
//$doctrineAutoloader->register();
spl_autoload_unregister($doctrineAutoloader);
$autoloader = Zend_Loader_Autoloader::getInstance();
// Push the doctrine autoloader to load for the Doctrine\ namespace
$autoloader->pushAutoloader($doctrineAutoloader, 'Doctrine');
$classLoader = new \Doctrine\Common\ClassLoader('Entities', realpath(__DIR__ . '/models/'), 'loadClass');
$autoloader->pushAutoloader(array($classLoader, 'loadClass'), 'Entities');
$classLoader = new \Doctrine\Common\ClassLoader('Symfony', realpath(__DIR__ . '/../library/Doctrine/'), 'loadClass');
$autoloader->pushAutoloader(array($classLoader, 'loadClass'), 'Symfony');
$doctrineConfig = $this->getOption('doctrine');
$config = new \Doctrine\ORM\Configuration();
$cache = new \Doctrine\Common\Cache\ArrayCache;
$config->setMetadataCacheImpl($cache);
$config->setQueryCacheImpl($cache);
$driverImpl = new Doctrine\ORM\Mapping\Driver\YamlDriver(APPLICATION_PATH . '/../configs/mappings/yaml');
//$driverImpl = $config->newDefaultAnnotationDriver($doctrineConfig['path']['entities']);
$config->setMetadataDriverImpl($driverImpl);
$config->setProxyDir(APPLICATION_PATH . '/../proxies');
$config->setProxyNamespace('App\Proxies');
$connectionOptions = array(
'driver' => $doctrineConfig['conn']['driv'],
'user' => $doctrineConfig['conn']['user'],
'password' => $doctrineConfig['conn']['pass'],
'dbname' => $doctrineConfig['conn']['dbname'],
'host' => $doctrineConfig['conn']['host']
);
$registry = Zend_Registry::getInstance();
$registry->entitymanager = $em;
return $em;
}
Schema etc
I use yaml as you seen above, I haven't looked through the tutorial but I've used the command line tool that works like a charm, my doctrine.php (located in APPLICATION/bin):
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/..'));
// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'development'));
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path()
)));
/** Zend_Application */
require_once 'Zend/Application.php';
// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/../configs/application.ini'
);
$application->getBootstrap()->bootstrap('doctrine');
require_once __DIR__ . '/../Bootstrap.php';
$em = $application->getBootstrap()->getResource('doctrine');
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em, APPLICATION_PATH . "/configs/mappings")
));
\Doctrine\ORM\Tools\Console\ConsoleRunner::run($helperSet);
You first have to generate your entities:
Generate all the models without deleting, creates also annotations -
./doctrine orm:generate-entities ~/Public/my_app/application/models/ --regenerate-entities 0 --generate-annotations 1
then generate your schema
./doctrine orm:schema-tool:create --dump-sql
or
./doctrine orm:schema-tool:update --dump-sql
the proxies are not really a part of your models, it's just used by Doctrine internally so I've put it as a separate entity from the models folder but I guess it doesn't really matter:
./doctrine orm:generate-proxies ~/Public/my_app/proxies/
Remember to add write permissions to the proxies for apache group.
Hmm... guess I didn't quite explain Jeboy's solution but perhaps my code helps you get started, it took me a while but once it's up and running it works like a charm :)
PS Don't forget the "namespace Entities;" in each of your models (it should be generated automatically)
I try to write test for controller. I use OS Windows, zend framework and my libraries are in C:/library which is added to the include_path of php.ini.
When I run test testLoginAction I get an error No default module define for the application. But I don't use modules at all. Do you know how to solve this problem?
IndexControllerTest.php
class Controller_IndexControllerTest extends ControllerTestCase
{
public function testIsEverythingOK()
{
$this->assertTrue(true);
}
public function testLoginAction()
{
$this->dispatch('/login/index');
$this->assertModule('default');
$this->assertController('login');
$this->assertAction('index');
}
}
ControllerTestCase.php
require_once 'Zend/Application.php';
require_once 'Zend/Controller/Action.php';
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
protected $_application;
public function setUp()
{
$this->bootstap = array($this, 'appBootstrap');
parent::setUp();
}
public function appBootstrap()
{
// require dirname(__FILE__) . '/bootstrap.php';
$this->front->setControllerDirectory('../application/controllers');
$this->_application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini');
$this->_application->bootstrap();
}
}
My phpunit.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<phpunit bootstrap="./application/bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="true"
syntaxCheck="true">
<!-- запускаем все тесты из корневой директории -->
<testsuite name="Main Test Suite">
<directory>./</directory>
</testsuite>
<filter> <!-- смотрим лишь на следующие директории -->
<whitelist>
<directory suffix=".php">../application</directory>
<!-- <directory suffix=".php">../library</directory>-->
<exclude>
<directory suffix=".phtml">../application</directory>
<directory>../application/forms</directory>
<directory>../application/models</directory>
<directory>../library</directory>
<file>../application/Bootstrap.php</file>
</exclude>
</whitelist>
</filter>
<logging>
<!-- логирование и создание отчета -->
<log type="coverage-html" target="./report" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70"/>
</logging>
</phpunit>
My bootstrap.php in tests/application:
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../../application'));
// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
/** Zend_Application */
require_once 'Zend/Application.php';
require_once 'ControllerTestCase.php';
My Base class for tests:
require_once 'Zend/Application.php';
require_once 'Zend/Controller/Action.php';
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
protected $_application;
public function setUp()
{
$this->bootstap = array($this, 'appBootstrap');
parent::setUp();
}
public function appBootstrap()
{
// require dirname(__FILE__) . '/bootstrap.php';
$this->front->setControllerDirectory('../application/controllers');
$this->_application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini');
$this->_application->bootstrap();
}
}
Best regards, Oleg.
Make sure your application.ini does not contain configuration like resources.frontController.moduledirectory = APPLICATION_PATH "/modules" or resources.frontController.params.prefixDefaultModule = 1 or resources.modules[] =
You need to modify your setUp() method from the ControllerTestCase class, after parent::setUp() line:
$this->getFrontController()->setControllerDirectory(APPLICATION_PATH . '/controllers');
and remove the following line from your appBoostrap method:
$this->front->setControllerDirectory('../application/controllers');
$this->front-> won't work because the front controller property is $this->frontController-> or $this->getFrontController()->.
Even so, your tests probably won't work anyways because of the way you're bootstrapping. Are you configuring your front controller from an ini configuration file? If yes, then you don't need to configure the frontController in your tests, you need to configure your bootstrap by way of Zend_Application.
$this->bootstrap = new Zend_Application(
'testing',
APPLICATION_PATH . '/configs/application.ini'
);
You won't need to call bootstrap() on your Zend_Application instance because Zend_Test_PHPUnit_ControllerTestCase will do that when you dispatch a request.
So your base class might loook like this:
class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
public function setUp()
{
// Assign and instantiate in one step:
$this->bootstrap = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
parent::setUp();
}
}
And your controller test, extending your base class, will look like this:
class Controller_IndexControllerTest extends ControllerTestCase
{
public function testIsEverythingOK()
{
$this->assertTrue(true);
}
public function testLoginAction()
{
$this->dispatch('/login/index');
$this->assertModule('default');
$this->assertController('login');
$this->assertAction('index');
}
}
Done.
Resources
Bootstraping your TestCase