Autoloading class files for PHPUnit - php

So, I am just playing around with PHPUnit, I don't really need it but I want to learn how it works so I am trying it out on a random class in a plugin of mine.
The issue I have rn is that whenever I run phpunit I says the Plot class in my test was not found. In my composer.json file I have
{
"require": {
"phpunit/phpunit": "^8.5"
},
"autoload":{
"psr-4" : { "\\mohagames\\PlotArea\\utils\\" : "src/mohagames/PlotArea/utils/"}
}
}
And my Plot.php file is in the C:\Users\moham\Documents\GitHub\PlotArea\src\mohagames\PlotArea\utils\ directory and has the mohagames\PlotArea\utils namespace
But for some reason it still says
C:\Users\moham\Documents\GitHub\PlotArea>C:\Users\moham\Documents\Github\PlotArea\vendor\bin\phpunit --debug
PHPUnit 8.5.0 by Sebastian Bergmann and contributors.
Runtime: PHP 7.3.4
Configuration: C:\Users\moham\Documents\GitHub\PlotArea\phpunit.xml
Test 'SampleTest::testPlot' started
Test 'SampleTest::testPlot' ended
Time: 95 ms, Memory: 4.00 MB
There was 1 error:
1) SampleTest::testPlot
Error: Class 'Plot' not found
C:\Users\moham\Documents\GitHub\PlotArea\tests\unit\SampleTest.php:8
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
And the SampleTest test class:
<?php
use PHPUnit\Framework\TestCase;
class SampleTest extends TestCase{
public function testPlot(){
$plot = new Plot();
}
}
I've tried all sort of solutions on the internet but none of them worked

Like Alister pointed out importing the class first works otherwise, PHP doesn't know what class the code is referring to.
<?php
use PHPUnit\Framework\TestCase;
use mohagames\PlotArea\utils\Plot;
class SampleTest extends TestCase{
public function testPlot(){
$plot = new Plot();
}
}

Related

Laravel 5.3 - Win10 - PHPUnit - Test code or tested code did not (only) close its own output buffers

Laravel 5.3, windows 10, VS code.
PHPUnit is marking the simplest of tests as 'Risky'.
Any ideas why?
I've tried all sorts of PHPUnit settings to switch of that 'Risky' output buffers error and this is the simplest test so I'm unsure where to start as to why it's happening.
VS Code terminal output...
C:/Source/laravel/vendor/bin/phpunit.bat -v -c
C:/Source/laravel/phpunit.xml ./laravel/tests/ExampleTest.php PHPUnit
5.6.2 by Sebastian Bergmann and contributors.
Runtime: PHP 7.0.12 with Xdebug 2.4.1 Configuration:
C:\Source\laravel\phpunit.xml R
1 / 1 (100%) Time: 562 ms, Memory: 28.00MB There was 1 risky test: 1)
ExampleTest::testBasicExample Test code or tested code did not (only)
close its own output buffers
Controller.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class TestController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
}
public function index()
{
return 'OK';
}
}
Test
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
/**
* A basic functional test example.
*
* #return void
*/
public function testBasicExample()
{
$this->visitRoute('test')
->seeText('OK');
}
}
Route:
Route::get('/test', 'TestController#index')->name('test');
I just figured this out... the issue was with the TestCase 'requiring/including' the wp-load.php file as I use some wordpress functions within my controllers. Remove that and it's fine.

Laravel Database Factory Files not being called

I'm trying to test a model I've created, and I'm getting the error:
InvalidArgumentException: Unable to locate factory with name [default]
[App\Company].
Here's what my very simple model looks like:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function incidents()
{
return $this->hasMany(Incident::class);
}
}
here's the factory:
<?php
$factory->define(\App\Company::class, function () {
return [
'name' => 'ACME Company'
];
});
and the setup method in my unit test that's throwing the error:
<?php
use Illuminate\Foundation\Testing\DatabaseMigrations;
class CompanyModelTest extends TestCase
{
use DatabaseMigrations;
public function setUp()
{
factory(\App\Company::class)->create();
}
When I run the test I get this:
laradock#63912b4222e6:/var/www/laravel$ vendor/bin/phpunit
PHPUnit 5.5.6 by Sebastian Bergmann and contributors.
E 1 / 1 (100%)
Time: 528 ms, Memory: 4.00MB
There was 1 error:
1) CompanyModelTest::testCompanyName
InvalidArgumentException: Unable to locate factory with name [default] [App\Company].
/var/www/laravel/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:126
/var/www/laravel/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2280
/var/www/laravel/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:139
/var/www/laravel/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:106
/var/www/laravel/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:84
/var/www/laravel/tests/CompanyModelTest.php:13
So far I've tried the suggestions on this other Stackoverflow question about the same error, and also this one.
I've tried moving my new factory into the ModelFactory.php file that's there by default and I've tried using defineAs() instead of define.
I've cleared the cache and run composer dump-autoload as suggested in other posts around the web.
I've dumped out the contents of FactoryBuilder::definitions which is empty, and that's what's causing the exception to be thrown.
I've confirmed that none of the factory files in database\factories directory are being called with debug code & a line that would cause a parse error.
Why aren't those files being called as per the documentation?
In my situation the TestCase was wrong class.
class CompanyModelTest extends TestCase
Which TestCase do you extend? I had
use PHPUnit\Framework\TestCase;
Instead of Laravel's own. Now it is working!
use Tests\TestCase;
Make sure you extend the correct TestCase class.

Mock Composer in PHPUnit is actually running

I'm building a PHP application that needs to access Composer directly. In order to test the application, however, I don't actually want to run composer, so I'm trying to mock it.
<?php
namespace MyNamespace;
use Composer\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
class MyTest extends \PHPUnit_Framework_TestCase {
public function testComposer()
{
/** #var Application|\PHPUnit_Framework_MockObject_MockObject $composer */
$composer = $this->getMockForAbstractClass(Application::class);
$composer
->expects($this->any())
->method('run')
->will($this->returnValue(true));
$this->assertTrue(
$composer->run(new ArrayInput(['command' => 'install']))
);
}
}
This actually runs the code:
$ bin/phpunit -c phpunit-fast.xml tests/MyTest.php
PHPUnit 4.8.10 by Sebastian Bergmann and contributors.
Runtime: PHP 5.6.13-1+deb.sury.org~trusty+3 with Xdebug 2.3.2
Configuration: phpunit-fast.xml
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Nothing to install or update
Generating autoload files
I've tried various combinations of ->getMock (which completely fails) and ->getMockBuilder but it always seems to actually use the ->run method rather than the stub.
I assume it is somehow replacing these method inside itself, but if that's the case, how to I prevent it?
Update
It was asked as to why I use getMockForAbstractClass rather than just getMock. When using getMock I get the following output:
PHPUnit 4.8.10 by Sebastian Bergmann and contributors.
Runtime: PHP 5.6.13-1+deb.sury.org~trusty+3 with Xdebug 2.3.2
Configuration: phpunit.xml.dist
E
Time: 1.19 minutes, Memory: 4.50Mb
There was 1 error:
1) MyNamespace\MyTest::testComposer
PHPUnit_Framework_MockObject_RuntimeException: Cannot mock Symfony\Component\Console\Application::setDispatcher() because a class or interface used in the signature is not loaded
tests/MyTest.php:22
Caused by
ReflectionException: Class Symfony\Component\EventDispatcher\EventDispatcherInterface does not exist
tests/MyTest.php:22
FAILURES!
Tests: 1, Assertions: 0, Errors: 1.
This is despite the fact that just using $composer = new Application(); works fine. In fact, if I add that line above the test, it still claims that an class or interface wasn't loaded, despite the object being instantiated correctly earlier.
I have 3 solutions to this:
1. Add Event Dispatcher yourself
Add "symfony/event-dispatcher" to your own require-dev
"require-dev" : {
...
"symfony/event-dispatcher" : "^2.1"
}
With the corrected test:
<?php
/**
* MyTest.php
*/
namespace MyNamespace;
use Composer\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
class MyTest extends \PHPUnit_Framework_TestCase {
public function testComposer()
{
/** #var Application|\PHPUnit_Framework_MockObject_MockObject $composer */
$composer = $this->getMock(Application::class);
$composer
->expects($this->any())
->method('run')
->will($this->returnValue(true));
$this->assertTrue(
$composer->run(new ArrayInput(['command' => 'install']))
);
}
}
Personal note: This feels like a dirty hack but is by far the easiest solution
2. Use Prophecy
Use prophecy alongside PHPUnit to mock the console.
"require-dev" : {
...
"phpspec/prophecy": "~1.0"
}
Now the test looks like this:
<?php
/**
* MyTest.php
*/
namespace MyNamespace;
use Composer\Console\Application;
use Prophecy\Prophet;
use Prophecy\Prophecy\ObjectProphecy;
use Symfony\Component\Console\Input\ArrayInput;
class MyTest extends \PHPUnit_Framework_TestCase {
public function testComposer()
{
$prophet = new Prophet();
$composerProphecy = $prophet->prophesize(Application::class);
$composerProphecy
->run(new ArrayInput(['command' => 'install']))
->willReturn(true);
/** #var Application $composer */
$composer = $composerProphecy->reveal();
$this->assertTrue(
$composer->run(new ArrayInput(['command' => 'install']))
);
}
}
Personal note: I'm not keen on telling the prophecy what methods will be called using magic methods as these upset my IDE.
3. Use Mockery
Another option for the mocking system.
"require-dev" : {
...
"mockery/mockery": "^0.9.4"
}
And the test:
<?php
/**
* MyTest.php
*/
namespace MyNamespace;
use Composer\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
class MyTest extends \PHPUnit_Framework_TestCase {
public function testComposer()
{
/** #var Application|\Mockery\MockInterface $composer */
$composer = \Mockery::mock(Application::class);
$composer
->shouldReceive('run')
->with(ArrayInput::class)
->andReturn(true);
$this->assertTrue(
$composer->run(new ArrayInput(['command' => 'install']))
);
\Mockery::close();
}
}
Personal note: Static usage, having to remember to clean up, and a mis-documented use of a variadic in shouldReceive made me very sad.
4. (Bonus) Fix Symfony Console
Seems unlikely but if anyone can work out how to fix #8200, then that would mean no one would have to use multiple mock frameworks (if you're already using PHPUnit anyway) or add dirty hacks to their require-dev for a single broken test.
I can't comment yet, sorry. :/
TL;DR: getMock variant works for me. Check your environment.
Getting composer via composer (in composer.json require "composer/composer": "#dev") makes the test (using getMock) pass for me.
Check which version of symfony you're using (mine is 2.7.4) and if you're using the phar version of composer (which you probably shouldn't).

Class 'Behat\Behat\Context\BehatContext' not found in PHP with Behat

I am trying to learn Behat using the tutorial on the website.
The first step goes OK, no errors appear.
But when I am changing the ls_project/features/bootstrap/FeatureContext.php, as shown in the tutorial second step, I am getting the following error: 'Behat\Behat\Context\BehatContext' not found.
The tutorial code, to which the change is applied:
# features/bootstrap/FeatureContext.php
<?php
use Behat\Behat\Context\BehatContext,
Behat\Behat\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
class FeatureContext extends BehatContext
{
/**
* #Given /^I am in a directory "([^"]*)"$/
*/
public function iAmInADirectory($dir)
{
if (!file_exists($dir)) {
mkdir($dir);
}
chdir($dir);
}
}
The full error log:
11:51:33 / ME : /var/www/test-driven/behat/ls_project
$ behat
# features/bootstrap/FeatureContext.php
PHP Fatal error: Class 'Behat\Behat\Context\BehatContext' not found in /var/www/test-driven/behat/ls_project/features/bootstrap/FeatureContext.php on line 10
PHP Stack trace:
PHP 1. {main}() /opt/Behat/bin/behat:0
PHP 2. Symfony\Component\Console\Application->run() /opt/Behat/bin/behat:31
PHP 3. Behat\Testwork\Cli\Application->doRun() /opt/Behat/vendor/symfony/console/Symfony/Component/Console/Application.php:121
PHP 4. Symfony\Component\Console\Application->doRun() /opt/Behat/src/Behat/Testwork/Cli/Application.php:90
PHP 5. Symfony\Component\Console\Application->doRunCommand() /opt/Behat/vendor/symfony/console/Symfony/Component/Console/Application.php:191
PHP 6. Symfony\Component\Console\Command\Command->run() /opt/Behat/vendor/symfony/console/Symfony/Component/Console/Application.php:892
PHP 7. Behat\Testwork\Cli\Command->execute() /opt/Behat/vendor/symfony/console/Symfony/Component/Console/Command/Command.php:241
PHP 8. Behat\Testwork\Tester\Cli\ExerciseController->execute() /opt/Behat/src/Behat/Testwork/Cli/Command.php:63
PHP 9. Behat\Testwork\Tester\Cli\ExerciseController->testSpecifications() /opt/Behat/src/Behat/Testwork/Tester/Cli/ExerciseController.php:106
PHP 10. Behat\Testwork\EventDispatcher\Tester\EventDispatchingExercise->test() /opt/Behat/src/Behat/Testwork/Tester/Cli/ExerciseController.php:137
PHP 11. Behat\Testwork\Tester\Runtime\RuntimeExercise->test() /opt/Behat/src/Behat/Testwork/EventDispatcher/Tester/EventDispatchingExercise.php:65
PHP 12. Behat\Testwork\Environment\EnvironmentManager->buildEnvironment() /opt/Behat/src/Behat/Testwork/Tester/Runtime/RuntimeExercise.php:67
PHP 13. Behat\Behat\Context\Environment\Handler\ContextEnvironmentHandler->buildEnvironment() /opt/Behat/src/Behat/Testwork/Environment/EnvironmentManager.php:69
PHP 14. Behat\Behat\Context\Environment\UninitializedContextEnvironment->registerContextClass() /opt/Behat/src/Behat/Behat/Context/Environment/Handler/ContextEnvironmentHandler.php:75
Could anyone please help me resolving this issue?
It appears you've installed Behat v3, but you're following Behat 2 docs.
Behat 3
Behat 3 doesn't have the Behat\Behat\Context\BehatContext class. It's got a Behat\Behat\Context\Context interface:
use Behat\Behat\Context\Context;
class FeatureContext implements Context
{
// ...
}
In composer.json:
{
"require-dev": {
"behat/behat": "~3.1"
},
"config": {
"bin-dir": "bin/"
}
}
Behat 2
Behat 2 uses the Behat\Behat\Context\BehatContext base class:
use Behat\Behat\Context\BehatContext;
class FeatureContext extends BehatContext
{
// ...
}
In composer.json:
{
"require-dev": {
"behat/behat": "~2.5"
},
"config": {
"bin-dir": "bin/"
}
}
In behat 3 there is different structure so you need to use new path to behat context which is in Behat/Behat/Context/Context
<?php
use Behat\Behat\Context\Context;
use Behat\MinkExtension\Context\RawMinkContext;
use Behat\Behat\Context\CustomSnippetAcceptingContext;
use Behat\Behat\Tester\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
class FeatureContext extends RawMinkContext implements Context {
}
So use this for example :-)

Running PHPUnit tests from directory with custom framework

For our project I have created a framework on top of the PHPUnit framework which helps us in some of the common tasks in writing unit tests.
This custom framework inherits from PHPUnit_Framework_TestCase and then modifies the mySetup() and adds bunch of useful functions for our code.
<?php
class OurUnitTestFramework extends PHPUnit_Framework_TestCase {
public $dbMock;
protected function mySetup (..) { ... }
protected function testHelper () { ... }
}
?>
Now in our test code we just extend OurUnitTestFramework and then write the tests.
<?php
require_once ("OurUnitTestFramework");
class DatabaseConnectionTest extends OurUnitTestFramework {
parent::setUp (..) { ... }
public function testSomeThing () { ... }
public function testSomeOtherThing () { ... }
}
?>
Till now we were running all the unit tests through Jenkins and it still is running fine but now when we try to run the tests in a folder it fails. All the tests inside the folder/sub-folder runs successfully but there is one failure:
[sumit#dev model]$ phpunit database
PHPUnit 3.5.14 by Sebastian Bergmann.
F........
Time: 0 seconds, Memory: 10.50Mb
There was 1 failure:
1) Warning
No tests found in class "OurUnitTestFramework".
FAILURES!
Tests: 9, Assertions: 30, Failures: 1.
I have a directory database which has sub directories and all the tests passes from that folder and its subfolder but I get failure from OurUnitTestFramework saying there is no tests found in this custom framework. So I am not able to understand why phpunit is running unit tests on the file which is included/extended in the test file?
We can simply choose to ignore this one error but I wanted to know if okay to leave like this or is there something that I need to configure to make it pass.
Thanks
Make 'OurUnitTestFramework' an abstract class.

Categories