Trying to integrate PHPUnit and my IDE (PhpStorm 2017.2). I'm executing the phpunit.phar file directly (version 5.7.21) as I don't use Composer and don't have it installed.
phpunit.xml
<phpunit bootstrap="phpunit-bootstrap.php">
<testsuites>
<testsuite name="Test suite">
<directory>./</directory>
</testsuite>
</testsuites>
</phpunit>
phpunit-bootstrap.php
spl_autoload_register('my_autoload');
/**
* #param string $className Fully qualified name to autoload
*/
function my_autoload($className){
require $_SERVER['DOCUMENT_ROOT'] . "\\$className.php";
}
This autoloader works fine when I execute my project files. However when I try to run any PHPUnit test, I see this error:
Fatal error: require(): Failed opening required '\Composer\Autoload\ClassLoader.php'
If I remove the autoload, then my project classes can no longer be found (same error, different class name).
Does PHPUnit depend on Composer being installed globally and available on the system path?
Update 1
Following kuba's suggestion in comments, I changed the autoload to:
require __DIR__ . "\\$className.php";
New error:
Fatal error: require(): Failed opening required 'C:\project-root\Composer\Autoload\ClassLoader.php'
I needed to adjust my autoloader to do nothing when PHP tried to load Composer\Autoload\ClassLoader.php. So I changed my Autoloader from:
function my_autoload($className){
require __DIR__ . "\\$className.php";
}
to
function my_autoload($className){
$path = __DIR__ . "\\$className.php";
if (file_exists($path)) require $path;
}
Related
I'm starting to setup PHPUnit (v4.8) to be used in my 'legacy' code (it's not so legacy, but it have bad programming practices).
The structure of my folders is as follows
/home
-phpunit.xml
/folder1
/folder2
/folder3
/vendor
/tests
-Test1.php
/includes
-functions.php
/libs
-User.php
-TableClass.php
....
functions.php
<?php
//require_once $_SERVER['DOCUMENT_ROOT'] . "/home/vendor/autoload.php" ;
require_once $_SERVER['DOCUMENT_ROOT'] . "/home/includes/libs/table_classes/User.php" ;
?>
I have commented that line, because I think composer automatically loads it. Question 1, Am I Rigth? (because phpunit get automatically recognized inside my Test class...)
Test1.php
<?php
class Test1 extends PHPUnit_Framework_TestCase
{
public function testSomething()
{
// $something = getColNameByStatusId(1);
$this->assertEquals(1,2);
}
}
?>
phpunit.xml
<phpunit bootstrap="includes/functions.php" colors="true">
<testsuite name="Test1" >
<directory>./tests</directory>
</testsuite>
</phpunit>
Then I Execute phpunit in command line
My functions.php works fine in my code, of course with no composer integration, but when It's loaded with phpunit it 'breaks', I get the following error:
Warning: require_once(/home/includes/libs/table_classes/User.php): failed to open stream: No such file or directory in C:\wamp\www\home\includes\functions.php on line 18
I think I'm missing the 'loading' stuff for phpunit. My code doesn't use namespaces and PSR-0 neither PSR-4.
Question 2- How to properly load files in this case?
My goal is to load functions.php then it will load all other 'table' classes for doing my tests
Replace $_SERVER['DOCUMENT_ROOT'] with __DIR__ and adjusted the paths accordingly, and everything worked fine.
PHPUnit does not set $_SERVER['DOCUMENT_ROOT'] so It was not finding my files. Apache's do that. So the CLI of PHPUnit couldn't find it.
Hope it helps someone else.
I think it is better to start using PHPUnit by running
phpunit --generate-configuration
and follow some simple questions.
To autoload 'functions.php' and other table 'classes', you may try via composer.json autoload.
"autoload": {
"psr-4": {
"Model\\": "libs/"
}
}
Here is the link with autoload for your reference.
I have a fairly simple problem that I cannot seem to figure out.
I am developing an OOP-based PHP application using the Composer Dependency Manager, PHPUnit for testing. I am hosting the repository on GitLab and am using GitLab-CI to run the PHPUnit tests.
My file directory is fairly simple:
├──_data
├──_2016
├──_federal
├──fit.json
├──_libs
├──_paycheckCalculator
├──paycheck.php
├──taxCalc.php
├──_public_html
├──index.php
├──_vendor
├──[composer dependencies]
├──autoload.php
├──_tests
├──paycheckTest.php
├──taxCalcTest.php
├──_templates
├──[Twig templates]
taxCalc.php contains:
public static function calcFIT($taxableWages, array $taxStatus, int $frequency = 52):float {
$fitFile = "../data/2016/federal/fit.json";
...
That works just fine on my production server and I can run the PHPunit tests just fine via PHPUnit integration with PhpStorm, but when I try to get GitLab-CI to work I consistently get an error:
...
$ vendor/bin/phpunit --configuration phpunit.xml PHPUnit 5.5.4 by
Sebastian Bergmann and contributors.
EE..EII 7
/ 7 (100%)
Time: 32 ms, Memory: 4.00MB
There were 3 errors:
1) paycheckTest::calcNetTest
file_get_contents(../data/2016/federal/fit.json): failed to open
stream: No such file or directory
/builds/calebrw/paycheckCalculator/libs/paycheckCalculator/taxCalc.php:100
/builds/calebrw/paycheckCalculator/libs/paycheckCalculator/paycheck.php:49
/builds/calebrw/paycheckCalculator/libs/paycheckCalculator/paycheck.php:28
/builds/calebrw/paycheckCalculator/tests/paycheckTest.php:34
2) paycheckTest::calcTaxesTest
file_get_contents(../data/2016/federal/fit.json): failed to open
stream: No such file or directory
/builds/calebrw/paycheckCalculator/libs/paycheckCalculator/taxCalc.php:100
/builds/calebrw/paycheckCalculator/tests/paycheckTest.php:58
3) taxCalcTest::calcFITTest
file_get_contents(../data/2016/federal/fit.json): failed to open
stream: No such file or directory
/builds/calebrw/paycheckCalculator/libs/paycheckCalculator/taxCalc.php:100
/builds/calebrw/paycheckCalculator/tests/taxCalcTest.php:53
ERRORS! Tests: 7, Assertions: 11, Errors: 3, Incomplete: 2. ERROR:
Build failed: exit code 1
My .gitlab_ci.yml is as follows:
# Select image from https://hub.docker.com/_/php/
image: php:7.0
# Select what we should cache
cache:
paths:
- vendor/
before_script:
# Install git, the php image doesn't have installed
- apt-get update -yqq
- apt-get install git -yqq
# Install composer
- curl -sS https://getcomposer.org/installer | php
# Install all project dependencies
- php composer.phar install
PHPUnit:testsuite:
script:
- vendor/bin/phpunit --configuration phpunit.xml
My phpunit.xml file contains:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.5/phpunit.xsd"
colors="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="false">
<testsuites>
<testsuite name="Paycheck Tests">
<directory>tests/</directory>
</testsuite>
</testsuites>
<php>
<includePath>/builds/calebrw/paycheckCalculator</includePath>
</php>
</phpunit>
Please note that I've used this with or without the <includePath> tag and there is no difference if I use <includePath>/../</includePath> or anything else for that matter.
I appreciate any help you can give.
EDIT:
I finally got this to work. I added a function (in the global space for now) to my config.php file:
/**
* Required Functions
*/
function getDirectory(bool $html = false):string
{
$htmlBaseDirectory = '/webprojects/paycheckCalculator';
if ($html == true) {
return $htmlBaseDirectory;
} else {
return dirname(__DIR__);
}
}
That meant I could update my index.php:
require_once('config.php'); // Configuration Variables
require_once( getDirectory() . '/vendor/autoload.php'); // Composer Autoload
$dir = getDirectory(true) . $htmlPublicDirectory; // Combined variable needed for Twig compatibility
but I was still having problems with the GitLab-Ci runner having yet a completely different environment that doesn't call my config.php at all, so I added a fix (or hack really) to get the test to pass to taxCalc.php:
if (getenv('CI_BUILD_ID') !== false) {
define('MAIN_PATH', '/builds/calebrw/paycheckCalculator/');
} else {
define('MAIN_PATH', dirname(__DIR__));
}
...
class taxCalc
{
...
public static function calcFIT($taxableWages, array $taxStatus, int $frequency = 52):float {
$fitFile = MAIN_PATH . "/data/2016/federal/fit.json";
And now the build passes.
Thanks for all the help to both people who responded.
Make sure that the file is commited (usually you don't commit data you may place it under resources). I think you did already.
The second thing is also just a suggestion:
define a PATH constant and use this. Because in your case you never know where is your current working directory.
Define a bootstrap file in phpunit and define the MAIN_PATH. Example:
<?php
define('MAIN_PATH', dirname(__DIR__));
require MAIN_PATH . '/vendor/autoload.php';
In the index you have to provide this MAIN_PATH too and in calcFit you write:
<?php
function calcFit() {
$fitFile = MAIN_PATH . '/data/2016/federal/fit.json';
}
The issue is very probably that you are using a relative path in your require. See here for explanations and solutions : PHP - Failed to open stream : No such file or directory
I have chosen to use a Phar of PHPUnit (phpunit-4.8.26.phar) to unit test my custom built PHP Framework and Application. The reason I am using the old stable release is because I need compatibility with PHP 5.4.29.
The reason I have chosen not to use Composer to get PHPUnit is because it's tends to pollute my vendors folder with dependencies. I like to keep it as lean as possible.
I am using Windows 7 Pro SP1, WampDeveloper v5.4.0.1, ProPhpStorm 2016.1.2, Phing and a whole bunch of other cool stuff to do my thing.
The Problem
I CAN run a passing unit test successfully from within PhpStorm.
I CAN run a group of passing unit tests successfully from within PhpStorm.
I CAN NOT run a FAILING unit test successfully from within PhpStorm.
I CAN run a passing unit test successfully from the command line.
I CAN run a group of passing unit test successfully from the command.
I CAN NOT run a FAILING unit test successfully from the command line.
Instead of PHPUnit display a typical test failure message it exits with the below errors:
Warning: require(Composer\Autoload\ClassLoader.php): failed to open stream: No such file or directory in D:\WampDeveloper\Websites\qclean.development\bootstrap\Autoloader.php on line 23
Fatal error: require(): Failed opening required 'Composer\Autoload\ClassLoader.php' (include_path='.;D:\WampDeveloper\Tools\PEAR\pear;D:\WampDeveloper\Tools\PEAR;D:\WampDeveloper\Components\Php\PEAR;D:\WampDeveloper\Tools\PHPMailer;') in D:\WampDeveloper\Websites\qclean.development\bootstrap\Autoloader.php on line 23
And a screen shot to expand on the above:
Supporting Info
My directory structure:
My unit test script ConfigurationTest.php
<?php
/**
* Created by PhpStorm
* User:
* Date: 04/06/16
* Time: 12:04 PM
*/
namespace nova\tests\configuration;
use PHPUnit_Framework_TestCase as TestCase;
/**
* Class ConfigurationTest
*
* #package nova\tests\configuration
*/
class ConfigurationTest extends TestCase
{
protected function setUp()
{
parent::setUp();
}
public function test()
{
$result = false;
$this->assertTrue($result);
}
protected function tearDown()
{
parent::tearDown();
}
}
My PHPUnit XML configuration file TestAll.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="../../../bootstrap/Start.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
syntaxCheck="false"
timeoutForSmallTests="1"
timeoutForMediumTests="10"
timeoutForLargeTests="60"
verbose="false">
<testsuites>
<testsuite name="Nova Framework Test Suite">
<!-- <directory>.</directory> -->
<directory>./configuration</directory>
<exclude>./input</exclude>
<exclude>./request</exclude>
<exclude>./security</exclude>
<exclude>./validation</exclude>
</testsuite>
</testsuites>
</phpunit>
And lastly my Autoloader Autoloader.php
<?php
// Ref: https://github.com/philsturgeon/fig-standards
/**
* Define the application autoloader function.
*/
function autoload($className)
{
$className = ltrim($className, '\\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strrpos($className, '\\'))
{
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $namespace) . '.php';
require $fileName;
}
/**
* Register the autoloader functions.
*/
spl_autoload_register('autoload');
The error and warning indicate the inability to load the Composer\Autoload\ClassLoader.php file. What I don't understand is why it is asking for this file when I am using a Phar? Reading snippets off the internet indicate the Phar should have an internal autoloader though I am unable to see one.
I do not want to have to install Composer just to get it's autoloader. That would defeat the purpose of trying to solely use the Phar.
I added the PHPUnit Phar path to my Windows %path% but this did not make any difference. I understand that this should be done if PHPUnit was installed using PEAR.
Any help on this 'hair pulling out matter' would be greatly appreciated...
If you look at the stack trace, you'll see that the error is triggered on class_exists. This function calls __autoload by default. This means that the autoloader you registered will be called. In this case it will be called for a class that exists outside of your project.
So you should add an extra file_exists check to your autoloader before requiring the file. You're requiring a file that doesn't exist.
if (file_exists($fileName)) {
require $fileName;
}
Or just suppress the error (require doesn't throw an exception, so use #):
#require $fileName;
All what you need to do it to go to Settings > Language & Frameworks > PHP > PHPUnit and Choose PHPUnit library - and set path to phpunit.phar, that's all.
Below are the paths where files are located,
src\TW\Talk\Entity\Talk.php
src\Tests\Talk\Entity\TalkTest.php
src\phpunit.xml.dist
In TalkTest.php, I have included PHPUnit and the entity Talk.
require_once 'TW/Talk/Entity/Talk.php';
require('PHPUnit/Autoload.php');
Class TalkTest extends PHPUnit_Framework_TestCase
{
...
}
In phpunit.xml.dist file, I have,
<phpunit>
<testsuites>
<testsuite name="TW">
<file>Tests/Talk/Entity/TalkTest.php</file>
</testsuite>
</testsuites>
</phpunit>
I am running phpunit command from src directory, I am getting error that Fatel Error: Class 'Tests\TW\Talk\Enity\Talk' not found.
For reference, I am referring to php-object-freezer-master which has similar structure.
Any idea why the TalkTest is not able to find Talk class ?
phpunit command is trying to find Talk entity in Tests folder.
Changing phpunit.xml.dist to
<phpunit bootstrap="loader.php">
<testsuites>
<testsuite name="TW_Talk">
<directory>Tests</directory>
</testsuite>
</testsuites>
</phpunit>
and loader file as,
<?php
function tw_test_autoloader($class) {
if(file_exists(__DIR__."\\" . $class . ".php"))
require_once(__DIR__."\\" . $class . ".php");
}
spl_autoload_register('tw_test_autoloader');
Worked for me.
But still if I replace directory tag to file
<file>Tests\TW\Talk\Entity\TalkTest.php</file>
It does not work.
Check your include_path:
echo get_include_path();
It should contain the directory to which your TW/Talk/Entity/Talk.php is relative. If it is not there, then you must add it either to php.ini or to PHPUnit's bootstrap.
You can easily test if PHP can find your file using your include path with this:
var_dump( stream_resolve_include_path('TW/Talk/Entity/Talk.php') );
I am trying to use PhpUnit with Composer. In this purpose I did:
1 Added phpunit to req composer section:
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"autoload": {
"psr-0": {"PhpProject": "src/"}
}
2 Installed what needed:
php composer.phar install --dev
Operation finished with success.
Installing phpunit/phpunit (3.7.6)
Downloading: 100%
Unfortunately when I want to run the tests, I get
./vendor/bin/phpunit PHP Fatal error: Call to a member function
add() on a non-object in /home/serek/php/project/tests/bootstrap.php
on line 12
Problem occurs because
return ComposerAutoloaderInit::getLoader(); in vendor/autoload returns NULL into test bootstrap.
Any idea how can it be solved without hacking Loader?
Code:
phpunnit.xml.dist
> <?xml version="1.0" encoding="UTF-8"?>
>
> <phpunit bootstrap="tests/bootstrap.php" colors="true">
> <testsuites>
> <testsuite name="PhpProject Test Suite">
> <directory>tests/PhpProject/</directory>
> </testsuite>
> </testsuites>
>
> <filter>
> <whitelist>
> <directory suffix=".php">src/PhpProject/</directory>
> </whitelist>
> </filter> </phpunit>
tests/bootstrap.php (here I need only autoloader)
> $loader = require_once __DIR__ . "/../vendor/autoload.php";
> $loader->add('PhpProject\\', __DIR__); //<- this is problematic line 12 (comments has 9 lines)
/../vendor/autoload.php
// autoload.php generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit::getLoader();
The issue is that PHPUnit already requires the autoload file, so your require_once call is not executed and therefore the return value is not set (php doesn't keep the return value of require calls so require_once breaks on that use case).
You can safely change it to a require because with recent composer versions the autoloader is not created twice anymore and requiring it many times just returns you the same instance every time.