GitLab-CI issues with file_get_contents during PHPUnit Tests - php

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

Related

phpunit / excluded files still returning warnings

using version 8.1.6, and Given the following phpunit.xml :
<phpunit bootstrap="vendor/autoload.php">
<testsuites>
<testsuite name="SlimSkeleton">
<directory>tests</directory>
<exclude>./tests/Functional/BaseTestCase.php</exclude>
</testsuite>
</testsuites>
</phpunit>
And the following directory structure :
./tests/Functional/serviceA/...
./tests/Functional/BaseTestCase.php
I keep getting the following output :
...
1) Warning
No tests found in class "Tests\Functional\BaseTestCase".
...
I run the suitr via a scripts command in composer.json :
{
...
"scripts": {
"test": "phpunit"
}
}
Is it expected ? Is there a way to silence this warning ?
phpunit by default finds *Test.php, so even without <exclude> in phpunit.xml it would ignore BaseTestCase.php by running composer test.
Using tests instead of tests/EmailTest would instruct the PHPUnit command-line test runner to execute all tests found declared in *Test.php sourcecode files in the tests directory.
https://phpunit.de/getting-started/phpunit-8.html
I see "No tests found" warning if I specify command-line argument like the below. But this is not the intended usage of BaseTestCase.php from Slim-Skelton.
$ composer test tests/Functional/BaseTestCase.php
> phpunit 'tests/Functional/BaseTestCase.php'
PHPUnit 8.1.6 by Sebastian Bergmann and contributors.
W 1 / 1 (100%)
Time: 21 ms, Memory: 4.00 MB
There was 1 warning:
1) Warning
No tests found in class "Tests\Functional\BaseTestCase".
WARNINGS!
Tests: 1, Assertions: 0, Warnings: 1.

phpunit impossible to follow the installation process

I have a lot of problems trying to intall phpunit, maybe my knowledge isn't enought or the guide is very incomplete.
First, the install, I tried all the ways, globally, with "downloaded PHAR file directly" or with "sudo apt-get install phpunit" but when I tried to do:
$phpunit -v
bash: /usr/bin/phpunit: No chuch file or directory
if I do:
$ ll /usr/local/bin (I know, the path is different, other unexplicable event)
-rwxr-xr-x 1 user user 2784899 abr 29 17:09 phpunit*
but
$ sudo phpunit --version
PHPUnit 7.1.5 by Sebastian Bergmann adn contributors.
ok, looks better, so I tried to make the first example
<?php
use PHPUnit\Framework\TestCase;
class StackTest extends TestCase
{
public function testPushAndPop()
{
$stack = [];
$this->assertSame(0, count($stack));
array_push($stack, 'foo');
$this->assertSame('foo', $stack[count($stack)-1]);
$this->assertSame(1, count($stack));
$this->assertSame('foo', array_pop($stack));
$this->assertSame(0, count($stack));
}
}
but it give me the next error:
PHP Fatal error: Class 'PHPUnit\Framework\Testcase' not found in /var/www/html/phpunit/index.php on line 4
I'm using Ubuntu 18 and php 7.2
Any idea?
When you are running PHPUnit from the command line, you also need to include a 'bootstrap' file - it can be as simple as the composer autoload.php file:
phpunit --bootstrap vendor/autoload.php
Longer term, that configuration would be put into the phpunit.xml file so it is read, and run automatically by PHPunit.
<!-- file: phpunit.xml
src/autoload.php would also include the ./vendor/autoload.php file
and do any other locally required setup -->
<phpunit bootstrap="src/autoload.php">
<testsuites>
<testsuite name="money">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>
Ok, I start to understand some things.
First #Sebastian Bergmann give me the clue, with this example, it works.
But if you start with the documentation you never found it. I think it's an error and can confuse a begginer like me.
Yet I can't install phpunit with PHAR or globally, maybe it could be a future new post.
Thanks for all

PHPUnit test error, cannot find class

I'm new in PHPUnit and unit-testing, so I was install PHPUnit and phar via composer and everything had been going fine until I was try to start my simple test. I'm using PhpStorm where I can see all classes were autoload, but when I trying to start my test I got an error:
Fatal error: Class 'PharIo\Manifest\Simple' not found in C:\xampp\htdocs\mydocs\
I don't understand why he is looking for It in folder upper than PHPUnit is exists ?
I was trying to configure autoload section in composer.json and checking settings in phpunit.xml but nothing works.
Add:
I have to reinstall PHPUnit without PharIO, so now I have a little bit of progress, now I have a situation where I can test my class if I make require_once line with a name of the tested class. It looks like:
require_once '../src/Simple.php';
class SimpleTest extends PHPUnit_Framework_TestCase
{
public function testAdd() {
$sum = new Simple();
$this->assertEquals(5, $sum->add(2, 3));
}
}
So my simple class is:
class Simple {
public function add($a, $b) {
return (int) $a + (int) $b;
}
}
But, of course, I want to use namespaces. I try to make some changes based on this question: Autoloading classes in PHPUnit using Composer and autoload.php (I was try even use that repo for test, but an error is still exists) but nothing works for me. I was try to edit my autoload section in the composer.json like this
"autoload": {
"psr-4": {
"app\\": "src/"
}
},
But an error is still exists, another words autoload cannot see It. I was create phpunit.xml and phpunit.dist.xml with a same settings
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/3.7/phpunit.xsd"
backupGlobals="true"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="./tests/bootstrap.php">
<testsuites>
<testsuite name="The project's test suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
</phpunit>
and I made tests/bootstrap.php too with
require_once '../vendor/autoload.php';
I know this is an old question, but maybe you need to do
composer dump-autoload for composer to generate the map of classes.
I wasted 30mins trying to understand why PHPUnit was giving me:
Cannot stub or mock class or interface XXX because it doesn't exists
You should specify the script with autoloading classes.
You can either specify the file with autoloading in XML-file, as suggested in the other answer, or just by specifying --bootstrap option in your command to run tests:
phpunit --bootstrap vendor/autoload.php tests
Composer's autoload relies on configuration located in the vendor/autoload.php file which needs to be loaded at some point in your execution thread. You application already includes this and that's why it works, but the tests use a different entry point so you need to configure it with a file called phpunit.xml.dist.
Assuming your file structure is something like:
app/
src/
tests/
bootstrap.php <- create it in your test folder
vendor/
...
composer.json
composer.lock
phpunit.xml.dist <- create it if does not exist
You can see the various options here, but for a basic config, you can use this.
File phpunit.xml.dist:
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/3.7/phpunit.xsd"
backupGlobals="true"
backupStaticAttributes="false"
bootstrap="tests/bootstrap.php">
</phpunit>
File tests/bootstrap.php:
require_once '../vendor/autoload.php';
You should run phpunit from the root.

PHPUnit in a legacy environment

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.

PHPUnit (Phar) Fatal Error Only When Test Fails

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.

Categories