Setup PHPUnit with Zend Test - php

I'm trying to start using PHPUnit with Zend Test for my Zend Framework application. I'm able to run the PHPUnit command from command line phpunit --configuration phpunit.xml. I've tried following this tutorial which is based off of Matthew Weier O'Phinney's blog post. I'm getting an error when PHPUnit tries to write the log file. Here's my phpunit.xml
<phpunit bootstrap="./Bootstrap.php" colors="true">
<testsuite name="Zend Framework Tests">
<directory>./</directory>
</testsuite>
<!-- Optional filtering and logging settings -->
<filter>
<whitelist>
<directory suffix=".php">../library/</directory>
<directory suffix=".php">../application/</directory>
<exclude>
<directory suffix=".phtml">../application/</directory>
</exclude>
</whitelist>
</filter>
<logging>
<log type="coverage-html" target="./log/report" charset="UTF-8" yui="true" highlight="true" lowUpperBound="50" highLowerBound="80"/>
<log type="testdox-html" target="./log/testdox.html"/>
</logging>
</phpunit>
My testing bootstrap:
<?php
//Set app paths and environment
define('BASE_PATH', realpath(dirname(__FILE__) . '/../'));
define('APPLICATION_PATH', BASE_PATH . '/application');
define('TEST_PATH', BASE_PATH . '/tests');
define('APPLICATION_ENV', 'testing');
//Set include path
set_include_path('.' . PATH_SEPARATOR . BASE_PATH . '/library' . PATH_SEPARATOR . get_include_path());
//Set the default timezone
date_default_timezone_set('America/Chicago');
?>
And my ControllerTestCase that I would like my testing controllers to extend:
<?php
require_once 'Zend/Application.php';
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
abstract class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
public $_application;
public function setUp()
{
//Override the parent to solve an issue with not finding the correct module
$this->bootstrap = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
parent::setUp();
}
}
?>
The error I get when PHPUnit tries to write the log file is:
Fatal error: Class 'Symfony\Component\Console\Command\Command' not found in C:\repositories\myfirstzend.com\includes\library\Doctrine\DBAL\Tools\Console\Command\ImportCommand.php on line 38
Any clues on what I'm doing wrong? I'm on PHP 5.4, Windows 7, XAMPP 8.0, Pear is up to date, and I have the latest PHPUnit.
Update If I change my Bootstrap.php to the following from Matthew Weier O'Phinney's blog:
<?php
/*
* Start output buffering
*/
ob_start();
/*
* Set error reporting to the level to which code must comply.
*/
error_reporting( E_ALL | E_STRICT );
/*
* Set default timezone
*/
date_default_timezone_set('GMT');
/*
* Testing environment
*/
define('APPLICATION_ENV', 'testing');
/*
* Determine the root, library, tests, and models directories
*/
$root = realpath(dirname(__FILE__) . '/../');
$library = $root . '/library';
$tests = $root . '/tests';
$models = $root . '/application/models';
$controllers = $root . '/application/controllers';
/*
* Prepend the library/, tests/, and models/ directories to the
* include_path. This allows the tests to run out of the box.
*/
$path = array(
$models,
$library,
$tests,
get_include_path()
);
set_include_path(implode(PATH_SEPARATOR, $path));
/**
* Register autoloader
*/
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();
/**
* Store application root in registry
*/
Zend_Registry::set('testRoot', $root);
Zend_Registry::set('testBootstrap', $root . '/application/bootstrap.php');
/*
* Unset global variables that are no longer needed.
*/
unset($root, $library, $models, $controllers, $tests, $path);
I continue to get the error about Symfony from Doctrine. I ensured that I installed pear.symfony.com/Yaml as well. So still broken.
If I remove the Doctrine reference from my app.ini for the application I'm testing (which means it doesn't get loaded), I still get the error. It almost feels like the loaders for each of the three parts (PHPUnit, ZF, Doctrine) are fighting each other. Is there a way around this?
Second update: I downgraded PHPUnit to 3.4.15 and I'm still having this issue. My next step is to go from PHP 5.4 to 5.3.x.
Third update: I am now on PHP 5.3.10 and am seeing the same error.
If there's more information you need, please let me know.

I'm missing the loading of the application in your bootstrap.
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
To give you an idea about what I have in my tests/bootstrap.php (this is auto-generated by zend tool since release-1.11.4)
<?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();
As mentioned by the Zend Framework manual, best is to use PHPUnit 3.4.15 although I could run my tests using PHPUnit 3.6.12 as I'm isolating my tests to focus on my business logic and not the logic of Zend Framework.
I also modified my phpunit.xml as well into the following:
<phpunit bootstrap="./bootstrap.php" colors="true">
<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>
<directory suffix=".php">../../application</directory>
<exclude>
<directory suffix=".php">../../library/Zend</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
I hope this solves many of your issues you're facing now.
Best regards,
Michelangelo

Related

How to unit test a Joomla 2.5 component

Can someone provide an example of how to unit test a Joomla 2.5 component? I'm working through this joomla mvc component example, which doesn't include unit tests, and I can't find a full example anywhere. My main questions are:
Where to put component test code
How to run component unit tests
Is my test code correct
The Joomla documentation seems incomplete and fragmented - I've read what I can find on unit testing (can't post links due to low rep), which seem to be about testing Joomla itself rather than extensions. The closest I've found is this, which I've based my dummy test on.
What I've done so far
Component directory structure:
helloworld/
admin/
...
tests/
bootstrap.php
phpunit.xml
modelHelloWorldsTest.php
site/
...
helloworld.xml
To run the tests, I install/copy the component to my Joomla installation. I then run the following command from ~joomla/administration/components/com_helloworld/tests:
php phpunit-4.2.phar --bootstrap bootstrap.php .
from which I receive
Fatal error: Class 'ContentController' not found in C:\inetpub\wwwroot\ws_cairnstest\administrator\components\com_helloworld\tests\modelsHelloWorldsTest.php on line 5
bootstrap.php:
<?php
error_reporting(E_ALL);
define('_JEXEC', 1);
define('BASEPATH',realpath(dirname(__FILE__).'/../../'));
define('JOOMLA_PATH',realpath(dirname(__FILE__).'/../../../../../'));
define('JOOMLA_ADMIN_PATH',realpath(dirname(__FILE__).'/../../../../'));
$_SERVER['HTTP_HOST'] = 'localhost';
$_SERVER['REQUEST_METHOD'] = 'GET';
if (file_exists(JOOMLA_ADMIN_PATH . '/defines.php'))
{
include_once JOOMLA_ADMIN_PATH . '/defines.php';
}
if (!defined('_JDEFINES'))
{
define('JPATH_BASE', JOOMLA_ADMIN_PATH);
require_once JPATH_BASE . '/includes/defines.php';
}
require_once JPATH_BASE . '/includes/framework.php';
require_once JPATH_BASE . '/includes/helper.php';
require_once JPATH_BASE . '/includes/toolbar.php';
define('JPATH_COMPONENT',JOOMLA_ADMIN_PATH.'/components/com_content');
$app = JFactory::getApplication('administrator');
include BASEPATH.'/controller.php';
modelsHelloWorldsTest.php:
<?php
class HelloWorldsTest extends \PHPUnit_Framework_TestCase {
public function testList(){
$c = new ContentController();
$model = $c->getModel('helloworlds');
$worlds = $model->getItems();
var_dump($worlds);
$this->assertNotEmpty($worlds);
}
}
phpunit.xml:
<phpunit bootstrap="bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
verbose="true">
</phpunit>
Unit tests for Joomla are typically written to use the PHP Unit framework
To answer your questions
Where to put component test code: at the top level of your repo as follows
Component repo directory structure:
src
admin/
site/
tests
How to run component unit tests: test execution follows this pattern
vendor/bin/phpunit --configuration phpunit.xml
additional details can be found in the php unit documentation https://phpunit.de/documentation.html
Is your test code correct: no
You failed to mock your class and methods with the getMockBuilder() for testing.
Here are some examples to look at
https://github.com/joomla-framework/database
https://github.com/joomla-extensions/weblinks

NetBeans's include path doesn't work

I have a NetBeansProject that works on ZendFramework (the library) and uses PHPUnit to do the tests but each time some function of the Zend Framework is called (the bootstrap file calls them for example) it gives a fatal error because it can't find those files:
Fatal error: require_once(): Failed opening required 'Zend/Db/Table/Abstract.php' (include_path='.;C:\xampp\htdocs\pear;C:\xampp\php\PEAR') in....
My bootstrap file looks like this:
<?php
ini_set('display_startup_errors', 1);
ini_set('display_errors', 2);
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'));
defined('LIBRARY_PATH')
|| define('LIBRARY_PATH', realpath(dirname(__FILE__) . '/../library'));
defined('TESTS_PATH')
|| define('TESTS_PATH', realpath(dirname(__FILE__)));
//Define constant global variable
defined('_FOO_ROOT_DIR_') || define('_FOO_ROOT_DIR_', dirname(dirname(__FILE__)));
defined('_FOO_APP_DIR_') || define('_FOO_APP_DIR_', _FOO_ROOT_DIR_ . '/application');
defined('_FOO_LIB_DIR_') || define('_FOO_LIB_DIR_', _FOO_ROOT_DIR_ . '/library');
defined('_FOO_PUBLIC_DIR_') || define('_FOO_PUBLIC_DIR_', _FOO_ROOT_DIR_ . '/public');
defined('_FOO_TEST_DIR_') || define('_FOO_TEST_DIR_', _FOO_ROOT_DIR_ . '/tests');
defined('_FOO_ZF_DIR_') || define('_FOO_ZF_DIR_', 'C:\zend\ZendFramework-1.11.11\library');
require_once 'Zend/Db/Table/Abstract.php';
.
.
.
.
#End of bootstrap.php
and that require_once is what triggers the error. If for example I modify the bootstrap file and instead of doing the require from 'Zend/Db/Table/Abstract.php' I do it from _FOO_ZF_DIR_.'/Zend/Db/Table/Abstract.php' then the problem gets solved, but I have to rewrite every single include from every single file of the Zend library.
The path to the framework on the include is correct, and I have configured my PHPUnit with the bootstrap file I partially copied above and that phpunit.xml that was already given to me by my partner who has the project set and running.
The phpunit.xml looks like this (I don't know if it's relevant to the topic):
<phpunit bootstrap="./bootstrap.php" colors="true">
<testsuite name="ApplicationTestSuite">
<directory>./application/</directory>
<directory>./library/</directory>
</testsuite>
<filter>
<whitelist>
<directory suffix=".php">../application</directory>
<exclude>
<directory suffix=".php">../application/modules/pal</directory>
<directory suffix=".phtml">../application/views</directory>
<file>../application/Bootstrap.php</file>
</exclude>
</whitelist>
</filter>
<logging>
<log type="coverage-html" target="./log/coveragereport" charset="UTF-8"
yui="true" highlight="false" lowUpperBound="35" highLowerBound="70"/>
</logging>
</phpunit>
I have also configured the Zend tab on the options tools, registering the provider and such.
So how could I fix this so that the NetBeans can detect that the includes have to be found not only in relation to the project folder but also in relation to the included library path?
I've also tried to include the library through the global php includes and the project specific ones (through project properties) and neither of them works...
Thank you in advance
Solved!
I forgot to include the path to the ZendFramework library on the php.ini file.
This is what I had:
include_path=".;C:\xampp\htdocs\pear;C:\xampp\php\PEAR"
And this is what is required for it to work:
include_path=".;C:\xampp\htdocs\pear;C:\xampp\php\PEAR;C:\zend\ZendFramework-1.11.11\library"
Regards!

'Class not found' when using namespaces in PHPUnit

I'm new to PHPUnit and am having some trouble setting it up to access my PHP files. The directory structure I'm using for my app is this:
./phpunit.xml
./lib/Application/
-> Dir1/File1.php (namespace = Application\Dir1)
-> Dir1/File2.php
-> Dir2/File1.php (namespace = Application\Dir2)
./tests/Application/Tests
-> Test1.php (namespace = Application\Tests)
-> Test2.php
In my PhpUnit.xml, I have:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit verbose="false">
<testsuites>
<testsuite name="Application">
<directory>./tests/Application/Tests</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="false"/>
<log type="json" target="/tmp/phpunit-logfile.json"/>
</logging>
<filter>
<whitelist>
<directory suffix=".php">./lib</directory>
</whitelist>
</filter>
</phpunit>
And in one of my test files, I open with:
namespace Application\Tests;
use Application\Dir1\File1;
class MyTest extends File1 {}
But it keeps on saying:
Class 'Application\Dir1\File1' not found
Where am I going wrong?
If you installed PHPUnit using Composer then you can use Composers autoloader. The easiest way to do so would be to add:
"autoload":{
"psr-0":{
"your-app-directory":""
}
}
to composer.json
Even if you use use, you still have to include the file, either by using include, require, include_once, or require_once, or by using spl_autoload_register to include the file, like so:
spl_autoload_register(function ($class)
{
include '\lib\\' . $class . 'php';
});
When you then try to use Application\Dir1\File1 the script will automatically run include '\lib\Application\Dir1\File1.php'
I had the same issue.
I'm using composer as well and the only thing that solved it for me was the following:
add to your composer.json file in the autoload section a class map section with your root namespace
"autoload": {
"classmap": ["namespaceRoot/"]
}
execute composer dump-autoload command in order to recreate your autoload files (with all the class mappings!)
I found this really useful class autoloader by Jonathan Wage which allows PHPUnit tests to access namespaces from different directories. In my bootstrap.php, I just specified the location and associated module namespace:
require_once 'SplClassLoader.php';
$classLoader = new SplClassLoader('Application', dirname(__FILE__) . '/../lib');
$classLoader->register();

Can't extend PHPUnit_Extensions_Database_TestCase

I had become totally convinced about TDD and trying to use it by the book, looking forward to have a near to 100% test coverage and always writing tests before new coding.
I'm using phpUnit over ZF and although I can feel some progress somedays, in others I feel like I'm totally stuck.
My application is very database centric and I am in need to begin to test (and code...) database persistence.
I was taking a look at slides from Testing Lamp Appplications Presentation by Stephenn Bergmann and it seems very clear and straightforward how to test database interaction.
But, always I try to use a class that extends PHPUnit_Extensions_Database_TestCase I have error messages about not finding some class at 'PHPUnit_Extensions_Database' namespace.
Probably I´m missing some crucial point, as I have the same problem when I try to follow any of others solutions and suggestions I can find, like an answer and a presentation that I can't link here because of my reputation...
In all cases, when I extends Database_TestCase, some class is not found.
I suspect that there is something related with the way I'm bootstraping, but I can't find what I'm doing wrong. The tests I wrote that extend ControllerTestCase work well.
I'm running over Xampp. phpUnit version os 3.6.10, php is 5.3.8, Zend Framework is 1.11.11
I'm using the following phpunit.xml as php configuration:
<phpunit bootstrap="./application/bootstrap.php" colors="true">
<testsuite name="Some">
<directory>./</directory>
</testsuite>
<filter>
<whitelist>
<directory suffix=".php">../application/</directory>
<directory suffix=".php">../library/MyApp/</directory>
<exclude>
<directory suffix=".phtml">../application/</directory>
<file>../application/Bootstrap.php</file>
<file>../application/modules/default/controllers/ErrorController.php</file>
</exclude>
</whitelist>
</filter>
<logging>
<log type="coverage-html" target="./log/report" charset="UTF-8" yui="true" hightlight="true" lowupperbound="50" highlowerbound="80">
<log type="testdox" target="./log/testdox.html">
</log></log></logging>
My Bootstrap.php is:
error_reporting(E_ALL | E_STRICT);
// 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/Application.php';
require_once 'ControllerTestCase.php';
and ControllerTestCase.php
require_once 'Zend/Application.php';
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
/**
* #var Zend_Application
*/
protected $application;
public function setUp() {
$this->bootstrap = array($this, 'appBootstrap');
parent::setUp();
}
public function appBootstrap() {
$this->application = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
$this->application->bootstrap();
}
}
And when I create a Test as, for exemple, this tryTest.php
require_once 'PHPUnit/Extensions/Database/TestCase.php';
class TryTest extends PHPUnit_Extensions_Database_TestCase {
/*** any test or even just getConnection ***/
}
I receive the following error message or something close to it in other ways I try:
Fatal error: Class 'PHPUnit_Extensions_Database_DefaultTester' not found in C:\xampp\php\PEAR\PHPUnit\Extensions\Database\TestCase.php on
line 132
Call Stack:
0.0003 326968 1. {main}() C:\xampp\php\phpunit:0
0.0141 745152 2. PHPUnit_TextUI_Command::main() C:\xampp\php\phpunit:46
0.0141 745568 3. PHPUnit_TextUI_Command->run() C:\xampp\php\PEAR\PHPUnit\TextUI\Command.php:130
0.4012 5280032 4. PHPUnit_TextUI_TestRunner->doRun() C:\xampp\php\PEAR\PHPUnit\TextUI\Command.php:192
0.7182 5750296 5. PHPUnit_Framework_TestSuite->run() C:\xampp\php\PEAR\PHPUnit\TextUI\TestRunner.php:325
2.4058 11441872 6. PHPUnit_Framework_TestSuite->run() C:\xampp\php\PEAR\PHPUnit\Framework\TestSuite.php:705
2.4060 11442104 7. PHPUnit_Framework_TestSuite->runTest() C:\xampp\php\PEAR\PHPUnit\Framework\TestSuite.php:745
2.4060 11442104 8. PHPUnit_Framework_TestCase->run() C:\xampp\php\PEAR\PHPUnit\Framework\TestSuite.php:772
2.4061 11442104 9. PHPUnit_Framework_TestResult->run() C:\xampp\php\PEAR\PHPUnit\Framework\TestCase.php:751
2.4066 11441136 10. PHPUnit_Framework_TestCase->runBare() C:\xampp\php\PEAR\PHPUnit\Framework\TestResult.php:649
2.4079 11494800 11. PHPUnit_Extensions_Database_TestCase->setUp()
C:\xampp\php\PEAR\PHPUnit\Framework\TestCase.php:801
2.4080 11494832 12. PHPUnit_Extensions_Database_TestCase->getDatabaseTester()
C:\xampp\php\PEAR\PHPUnit\Extensions\Database\TestCase.php:202
2.4080 11494832 13. PHPUnit_Extensions_Database_TestCase->newDatabaseTester()
C:\xampp\php\PEAR\PHPUnit\Extensions\Database\TestCase.php:92
There is a DefaultTester.php at C:\xampp\php\PEAR\PHPUnit\Extensions\Database and I can't figure out what is going on...
I got to this configuration after following this [Zendcast from Jon Lebensold][2]. At that moment, I had some hard times trying to solve some problems, but after some help from #edorian I found that the main problem was between my chair and keyboard... :-/ Probably same situation now...
I even tryed to create a MapperTestCase in a similar way as Jon built his ControllerTestCase.php file, but this didn't help me anyhow.
So, now I'm here, trying to get some help to find what is wrong with my environment or approach.
Not really sure if it has solved all problems, but searching at Stackoverflow, I´d find this question that reported something similar to mine:
require_once 'Zend/Loader/AutoLoader.php';
$autoloader = Zend_Loader_AutoLoader::getInstance();
$autoloader->registerNamespace('PHPUnit_');
When I tried to put the code above at my bootstrap.php, I could at least make $connection = new PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection($pdo, 'mydb'); works
I still can't understand why PHPUnit extensions weren't being find, but, at least I will can advance...

Zend Framework UnitTest

I tried to use Zend_Test_PHPUnit to write unit tests for my application, but I always just get
1) IndexControllerTest::testValidation
Failed asserting last controller used <"error"> was "test"
I have created a test controller but even there I cannot get it to work.
Can anyone help?
Thanks!
class TestController extends Zend_Controller_Action
{
public function indexAction()
{
print 'test';
}
}
Bootstrap is:
// 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();
phpunit.xml is:
<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>
<directory suffix=".php">../application/</directory>
</whitelist>
</filter>
</phpunit>
Test controller is
class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
public function setUp()
{
$this->bootstrap = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
parent::setUp();
}
public function testValidation()
{
$this->dispatch('/test/');
$this->assertController("test");
}
}
Looks like an error in your TestController.
Is your View available (/test/index.phtml)?
Good solution would be to check the thrown Exception (wrap the unit test in an Try/Catch Block and print to error log).
I was getting the exact same error, but due to a completely different problem.
A more general solution might be to add this into the test method
print_r(strip_tags(
$this->bootstrap
->getBootstrap()
->getResource('layout')
->content
)); die;
This is assuming that Zend_Layout is being used... It prints out the contents of the error.phtml file, so at least you can see exactly what is going on.
You should see something like:
An error occurred
Application error
Exception information:
Message: {Your Error Message will appear here}
Stack trace:
{A stack trace will follow...}
With your specific error message appearing after "Message:" and then a full stack trace after "Stack Trace:".
Hopefully this will at least help to debug the underlying issue

Categories