I'm calling phpunit with the argument being a directory (bonus questions: why can't it accept a list of files?) and it's now complaining about a class being declared more than once because of a file included in the previous test!
If i run phpunit firstTest.php; phpunit secondTest.php everything works
But phpunit ./ fails with PHP Fatal error: Cannot redeclare class X
my tests are basically:
include 'class_to_be_tested.php'
class class1Test extends...
and nothing else. And i'm using the option --process-isolation. I could add require_once on my classes, but that's not what i want to be able to test them individually.
shouldn't phpunit follow best testing practices and run one test, clear whatever garbage it have, run another test on a clean state? or am i doing something wrong?
Since you have include rather than include_once and there is no other code shown in your question, the cannot redeclare error could also be that you are including the file again somewhere in the code under test.
Assuming that is not the case, there some behind the scenes things that happen with --process-isolation that can keep the global class declarations. This blog post gives more detail: http://matthewturland.com/2010/08/19/process-isolation-in-phpunit/
Basically, you will want to create your own base TestCase and override the run() method to set the preserveGlobalState to false. This should properly allow all your tests to run together.
The base class would look similar to this (taken from the blog post I referred to):
class MyTestCase extends PHPUnit_Framework_TestCase
{
public function run(PHPUnit_Framework_TestResult $result = NULL)
{
$this->setPreserveGlobalState(false);
return parent::run($result);
}
}
The way phpUnit works means that all your tests are run in the context of a single php program. phpUnit aims to isolate the tests from each other, but they are all run within the same program execution.
PHP's include statement will include the requested file regardless of whether it has been included before. This means that if you include a given class twice, you will get an error the second time. This is happening in your tests because each test is including the same file, but without any consideration to whether it's already been included by one of the other tests.
Solutions:
Wrap your include calls with a if(class_exists('classname')) so that you don't include the file if the class has already been defined.
Include the files in a phpUnit bootstrap file instead of in the tests.
Use include_once (or even require_once) instead of include.
Stop including files arbitrarily, and start using an autoloader.
Change:
include 'class_to_be_tested.php';
class class1Test extends...
to be:
include_once 'class_to_be_tested.php';
class class1Test extends...
In PHP you need to have a Really Good Reason to use the former.
Regarding why can't it accept a list of files?, I think the design decision is that you generally don't need to. However you can do it by creating a test suite in the phpunit.xml.dist file, see
http://www.phpunit.de/manual/current/en/organizing-tests.html#organizing-tests.xml-configuration
Related
This is my project path configuration
./create.php
/Install/Install.php
create.php
<?php
use Install\Install;
echo "Starting";
$install = new Install();
This gives me the error
PHP Fatal error: Uncaught Error: Class 'Install\Install' not found in /project/create.php:6
Install.php
<?php
namespace Install;
class Install
{
//whatever
}
Can someone explain me what is happening there ?
Obviously I guess that using a require_once line with my filename would probably fix the issue...but I thought using namespace and use import could prevent me from doing that like we do in classic framework like symfony / magento ?
I've seen some post speaking about autoloading, but i'm a little bit lost. Haven't been able to find a clear explanation on the other stack topic neither.
PHP compiles code one file at a time. It doesn't have any native concept of a "project" or a "full program".
There are three concepts involved here, which complement rather than replacing each other:
Namespaces are just a way of naming things. They allow you to have two classes called Install and still tell the difference between them. The use statement just tells the compiler (within one file) which of those classes you want when you write Install. The PHP manual has a chapter on namespaces which goes into more detail on all of this.
Require and include are the only mechanisms that allow code in one file to reference code in another. At some point, you need to tell the compiler to load "Install.php".
Autoloading is a way for PHP to ask your code which file it should load, when you mention a class it hasn't seen the definition for yet. The first time a class name is encountered, any function registered with spl_autoload_register will be called with that class name, and then has a chance to run include/require to load the definition. There is a fairly brief overview of autoloading in the PHP manual.
So, in your example:
use Install\Install; just means "when I write Install, I really mean Install\Install"
new Install() is translated by the compiler to new Install\Install()
the class Install\Install hasn't been defined; if an autoload function has been registered, it will be called, with the string "Install\Install" as input
that autoload function can then look at that class name, and run require_once __DIR__ . '/some/path/Install.php';
You can write the autoload function yourself, or you can use an "off-the-shelf" implementation where you just have to configure the directory where your classes are, and then follow a convention for how to name them.
If you want to Use class from another file, you must include or require the file.
Use require('Install.php'); before use Install\Install;.
If you are planning to do a big project I would recommend to use PHP frameworks rather than coding from scratch.
The following code is included by another file. My\Engine\Control is defined much earlier and extended all throughout my site with no issues. However in this one file I get the the error:
Fatal error: Class 'My\Engine\Control' not found in
/mnt/web/~/classes.php on line 6
<?php
namespace My\Engine;
// class Control {}
class RequiresAccount extends Control {
public function permissions() {
}
}
Yet when I try to put a dummy Control class in (uncomment the commented part) I get a different error.
Fatal error: Cannot declare class My\Engine\Control, because the name
is already in use in /mnt/web/~/Control.class.php on line 47
It seems impossible and I just can't figure it out. I write code like this all the time and just this one time...
All other files that require extending \My\Engine\Control function perfectly.
It seems that your using some custom autoload logic and some kind of optimizer which puts all the classes together into one file.
I would suggest sticking with PSR-4 standard & Composer library to support and maintain it.
This way your files will be organized and composer will take care of properly handling loading the files and optimizing the loading process for production. All you need to do is to include ./vendor/autoload.php file into your project and define the auto-loading strategy in composer.json file.
I've seen a lot of threads here and in other forums that asked this a lot of times, but I still see using the include function of PHP in the answers?
how can I use this function, not using totally the include function?
Thank you
how can I use this function, not using totally the include function
You cannot totally not use include and that is not the point of using autoloader as you usually need to at least include the autoloader ;). That autoloader is the regular PHP code that is being called by PHP when unknown class use is attempted in the code. It is expected to include right file to make the class known, and the code continues as you'd explicitely include right file by hand in your code. So the main benefit shows up when your code uses classed (OOP) - you do not need to care if you included the class you are about to instantiate the object of or not. You just do new Foo() or call Something::methodName() and if all is set up right it will work.
The function spl_autoload_register is used to register a callback into the autoloader queue.
The PHP autoloader is a functionality of the PHP interpreter that, when a class is not defined, calls the functions registered in the queue, one by one, asking them to load the class, until the class becomes available. It the class is still not available after all the functions were invoked, the interpreter triggers a fatal error.
The autoloader doesn't perform any magic. It is the entire responsibility of the registered functions to make the class available. Most of them use the name and namespace of the missing class to figure out the path of the file that contains the declaration of the class and include it.
That's how the thing works. There are not many ways to produce a class in PHP and, for a reusable autoloader callback, the list starts and ends with include1 (include_once, require or require_once can be used as well but they don't make any difference in this case.)
The autoloader callback itself stays in separate file (for reusability) and usually that file also contains its registration as autoloader callback (the call to spl_autoload_register). All your code have to do is to include this file once in every file that is an entry point of your application.
All things being equal, your application needs to use include at least once and once is also the maximum required number of usages for it. The autoloader callback also uses include (probably also only once) but you don't write autoloader callbacks every day. If you wrote one and you wrote it well you can reuse it. Most people never wrote an autoloader callback and they will never write one.
Using Composer is easy and if you follow the PSR-4 rules of naming the files of your project, Composer can generate an autoloader for your project that knows how to load your classes (behind the scene it uses include, of course). All you have to do is to run composer init in the root directory of your project, run composer install and write include 'vendor/autoload.php'; in the file that represents the entry-point of your application. No other uses of include are required.
1 An autoloader callback is not required to include another file to make the class available. It can generate the code of the class on the fly and eval()-uate it, but the use cases of such approach are very limited. It is used by the testing suites f.e., to generate mock classes.
i have fetal error message say :
Fatal error: Cannot redeclare class Database in C:\wamp\www\pets_new\lib\database.php on line 3
require_once("lib/message.php");
require_once("lib/user.php");
and all connect to database class
Class message
<?php
require('database.php');
class Message{
Class user :
<?php
require('database.php');
class User{
You include 2 files in a single "run". Think of it like this: All the included files are put together by PHP to create one big script. Every include or require fetches a file, and pastes its content in that one big script.
The two files you are including, both require the same file, which declares the Database class. This means that the big script that PHP generates looks like this:
class Message
{}
class Database
{}//required by message.php
class User
{}
class Database
{}//required by user.php
As you can see class Database is declared twice, hence the error.
For now, a quick fix can be replacing the require('database.php'); statements with:
require_once 'database.php';
Which checks if that particular file hasn't been included/required before. If it has been included/required before, PHP won't require it again.
A more definitive and, IMHO, better solution would be to register an autoloader function/class method, and let that code take care of business.
More on how to register an autoloader can be found in the docs. If you go down this route, you'd probably want to take a look at the coding standards concerning class names and namespaces here. If you conform to those standards, you don't have to write your own autoloader, and can simply use the universal class loader from Symfony2, or any other framework that subscribes to the PHP-FIG standards (like CodeIgnitor, Zend, Cake... you name it)
Try like this , while declaring class
if( !class_exists('database') ) {
require('database.php');
}
This means that you've already declared the class Database, the second time it's loaded (where ever the copy is), it's causing the error. We cannot see your content of the two files you've quoted. However, I'm sure if you look in both of them you'll find at least two creations of the class Database. One needs to be removed.
I've come across an unusual class loading problem in PHPUnit, initially experienced with 4.3.5 and now latest 4.4.2 as well (latest stable).
I have a bootstrap file which is loaded via a phpunit.xml automatically, which includes Composer's default autoloader and also my own autoloader. This works fine as it is. However, I discover that if I load a test class in the bootstrap, then PHPUnit isn't able to resolve the class name correctly, and it thus does not load.
I get this error:
Class 'test/unit/tests/UpdateAllTest' could not be found in '/full/project/path/webapp/test/unit/tests/UpdateAllTest.php'.
(My purpose in wanting to refer to a test class in the bootstrap is to add a database build method in each one, keeping it with the test file it pertains to. I plan to do this in the bootstrap rather than a setUp() method, as I want it to run once across all tests, not once per test method).
I've done a bit of light debugging inside PHPUnit itself (in particular PHPUnit_Runner_StandardTestSuiteLoader::load) and found the class name is incorrectly supplied as a path and not as a namespaced class name. Here is the relevant clause:
if (class_exists($suiteClassName, false)) {
$class = new ReflectionClass($suiteClassName);
if ($class->getFileName() == realpath($suiteClassFile)) {
return $class;
}
}
The value of $suiteClassName is test/unit/tests/UpdateAllTest, which is plainly not a namespaced anything - it should be Awooga\Testing\Unit\UpdateAllTest, something that is normally handled by a custom mapping in my autoloader.
I don't think I am doing anything particularly unusual with PHPUnit, and so find it unlikely that this is a bug that no-one else has thus far experienced. In these circumstances, do I maybe need to declare the class namespaces in the phpunit.xml or something unusual like that? Grasping at straws here!
Any thoughts as to what the cause of this seemingly trivial problem could be would be appreciated. In the meantime I will just move these set-up methods to a different file/class - not ideal but not the end of the world either. I'm on PHP 5.5.x and Ubuntu 12.04.
I haven't fixed this, but my build methods are now so long that it makes sense for them to appear in different classes anyway. I have a naming convention so that a test of *Test.php has a corresponding build class of *Build.php.
I use PHPUnit's bootstrap system to scan for build classes and to call a static build() within automatically.
Maybe you are also experiencing this problem.
Having the path as parameter is normal behavior at this point, check further down in PHPUnit_Runner_StandardTestSuiteLoader::load causes this confusing error message.