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...
Related
My problem with PHPUnit is quite simple: if the test class file is included in the bootstrap file, PHPUnit won't be able to find the test class.
You can easily recreate the issue:
The file hierarchy:
./tests/MyTest.php
./bootstrap.php
./phpunit.xml
phpunit.xml
<phpunit bootstrap="./bootstrap.php">
<testsuites>
<testsuite name="MyTest">
<directory>./tests</directory>
</testsuite>
</testsuites>
</phpunit>
bootstrap.php:
<?php
require __DIR__ .'/vendor/autoload.php';
require __DIR__ .'/tests/MyTest.php';
tests/MyTest.php
<?php
namespace App\Tests;
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase
{
public function testTrue()
{
$this->assertTrue(true);
}
}
In this case, when I run ./vendor/bin/phpunit, it returns "No tests executed!". And if I run ./vendor/bin/phpunit ./tests/MyTest.php, it returns "Class 'MyTest' could not be found in '[...]\tests\MyTest.php'.".
Now, if I remove the second require_once from autoload.php, both commands work as expected.
I've only seen a couple of similar issues on stack. They are six years old and have not been resolved, which makes me think that not allowing this way of loading classes is actually a design choice.
Could you please help me? Thank you!
I'm still new to phpUnit and I can't make my (very simple) test work.
<?php
use PHPUnit\Framework\TestCase;
class userTest extends TestCase {
public function testTrue() {
$this->assertTrue(true);
// This line wont work without autloader.php
$user = new User();
}
}
The problem is that I need to load all my classes from autoloader.php:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="inc/autoload.php"></phpunit>
But I'n those classes I have a lot of $SERVER variables, like
$_SERVER['REMOTE_ADDR']
$_SERVER['HTTPS']
$_SERVER['SERVER_NAME']
$_SERVER['DOCUMENT_ROOT']
$_SERVER['REQUEST_URI']
This is the error I get:
Notice: Undefined index: REMOTE_ADDR in /Applications/MAMP/htdocs/sakkadentrainer/classes/App.php on line 674
How can I make those variables work? I would prefer to kind of "fake" them as env.variables from the phpunit.xml file, but I don't know if that's possible.
Thanks for you help!
My Setup:
php 7.1.2, phpUnit 6.1.1, macOs Mojave, MAMP
SOLUTION:
https://phpunit.de/manual/6.5/en/appendixes.configuration.html#appendixes.configuration.php-ini-constants-variables
Referring to the Doc, you can Setting PHP INI settings, Constants and Global Variables, as example:
<php>
<server name="REMOTE_ADDR" value="127.0.0.1"/>
</php>
Hope this help
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
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
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