I've got a PHP script that runs at the command line, executing classes that are already unit tested with PHPUnit.
However, I'd like to verify that the script itself has no logical errors and runs properly.
// require classes
require_once 'injectedClass.php';
require_once 'DBClass.php';
require_once 'taskEngine.php';
$injectedObj = new injectedClass;
$dbObj = new DBClass;
$taskRunner = new taskEngine($injectedObj, $dbObj);
$taskRunner->task1()->task2();
$taskRunner->finish();
//etc
Updated Solution
It is as simple as djechelon's answer suggested, I was overthinking it. The solution is to create a PHPUnit test and pre-assign the variables passed into the taskRunner to mock objects. In the live script, a simple check before creating real objects allows the same script to be used for testing and production:
test:
$injectedObj = $this->getMock('injectedClass');
$dbObj = $this->getMock('DBClass');
require_once '/path/to/live/script.php';
$this->assertTrue($taskRunner->finished);
script:
// require classes
if(!isset($injectedObj)) {
$injectedObj = new injectedClass;
}
if(!isset($dbObj)) {
$dbObj = new DBClass;
}
$taskRunner = new taskEngine($injectedObj, $dbObj);
// run tasks
Can't you create a PHPUnit test for your script?
You could perform an integration test by hand, creating a script that runs your script with a set of given input parameters and compare its output to what you could expect.
Beware of the chicken-and-egg problem: your testing script cannot be tested itself by a test bench...
Anyway I'm not sure you need testing your script if it's so simple. A few manual runs might suffice...
Related
I'm writing controller testing unit with Fuelphp framework. And inside the code I'm trying to request application controller like this one :
$response = Request::force('controller_name/controller_method')->set_method('GET')->execute();
But this code unexpectedly exits the entire testing unit like PHP exit function. After trying to figure out what happened inside the core source code, I found out that in line 440 of https://github.com/fuel/core/blob/1.9/develop/classes/request.php forces the program to exit without any exception.
$this->controller_instance = $class->newInstance($this);
And before this code
$class = new \ReflectionClass($this->controller)
I'm using PHP 5.6.33 and Fuelphp 1.7.2 in my machine and I hope someone can help me with this error.
I think it's just a typo in your question but to be sure : you said
Request::force
instead of
Request::forge
Anyway, I have a lot of tests wrote in the same way but we add few lines before calling forge it :
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['HTTP_ACCEPT'] = 'application/json'; // this one may not be required for you
$_POST = array();
$_GET = array();
$request = \Request::forge('controller/action')->set_method('GET');
$request->execute();
We want to use the most current PHP_CodeCoverage API (https://github.com/sebastianbergmann/php-code-coverage) in our project.
To be sure it's really the case we just made an addtional script in bin/behat-coverage
#!/usr/bin/env php
<?php
require_once (\dirname(__FILE__).'/../vendor/autoload.php');
// Making coverage according to https://github.com/sebastianbergmann/php-code-coverage
$filter = new \SebastianBergmann\CodeCoverage\Filter();
$filter->addDirectoryToWhitelist(\dirname(__FILE__).'/../src');
$filter->removeDirectoryFromWhitelist(\dirname(__FILE__).'/../vendor');
$coverage = new \SebastianBergmann\CodeCoverage\CodeCoverage(new \SebastianBergmann\CodeCoverage\Driver\Xdebug(), $filter);
/**
* Creates the code coverage.
* NOTE! Behat calls the function exit (indirectly). So we have to make the coverage report in a function which
* is fired on exit.
*/
function ____on_behat_shutdown____() {
global $coverage;
$coverage->stop();
$writer = new \SebastianBergmann\CodeCoverage\Report\Html\Facade;
$writer->process($coverage, \dirname(__FILE__).'/../var/code-coverage-report');
}
register_shutdown_function('____on_behat_shutdown____');
$coverage->start('myproj');
require_once(\dirname(__FILE__).'/../vendor/behat/behat/bin/behat');
This seems to work fine.
But:
Is there a way to make execution speed the same as issuing vendor/bin/behat directly?
Is this the best way to use the most current PHP_CodeCoverage API?
Is there a way to make the output colorful again in Git Bash/Power Shell?
Is there a way to custom adjust colors in the shells mentioned above?
I am new on Symfony2 and I got blocked when trying to run an asynchronous command like this:
class MyCommand extends ContainerAwareCommand{
protected function configure()
{
$this
->setName('my:command')
->setDescription('My command')
->addArgument(
'country',
InputArgument::REQUIRED,
'Which country?'
)
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$country = $input->getArgument('country');
// Obtain the doctrine manager
$dm = $this->getContainer()->get('doctrine_mongodb.odm.document_manager');
$users = $dm->getRepository('MyBundle:User')
->findBy( array('country'=>$country));
}}
That works perfectly when I call it from my command line:
php app/console my:command uk
But it doesn't work when I call it trowh a Symfony2 Process:
$process = new Process("php ../app/console my:command $country");
$process->start();
I get a database error: "[MongoWriteConcernException] 127.0.0.1:27017: not master"
I think that means that the process is not getting my database configuration...
I just want to run an asynchronous process, is there other way to do it?
Maybe a way to call the Application Command that do not require the answer to keep going ?
Maybe I need to use injection?
PS: My current command is just a test, at the end it should be an 'expensive' operation...
Well, I found out what happened...
I use multiple environments: DEV, TEST and PROD.
And I also use differents servers.
So the DEV environment is my own machine with a simple mongodb configuration.
But the TEST environment is on other server with a replica set configuration...
Now the error get full sense: "[MongoWriteConcernException] 127.0.0.1:27017: not master"
To solve it, I've just added the environment parameter (--env=) to the process and everything worked like a charm:
$process = new Process("php ../app/console my:command $country --env=test");
Actually, to get the correct environment I use this:
$this->get('kernel')->getEnvironment();
Which let's my code as follows:
$process = new Process("php ../app/console my:command $country --env=".$this->get('kernel')->getEnvironment());
Maybe is not a beautifull way to do it, but it works for me :)
Disclamer: This might be a bit overkill for what you're trying to do :)
I would choose an opposite way to do it: pthreads
First, quick examination of StackOverflow showed me a really nice example of using pthreads: Multi-threading is possible in php
Then, knowing that you could invoke your command from another command:
http://www.craftitonline.com/2011/06/calling-commands-within-commands-in-symfony2/
... lets you piece all the parts. It's a bit complicated but it does the job.
In case you want to execute your code completely async in Symfony2/3 there is AsyncServiceCallBundle for that.
You should just call it like this:
$this->get('krlove.async')->call('your_service_id', 'method_name', [$arg1, $arg2]);
Internally it uses this approach to run your code in background.
I have a PHP deployment script that I want to run PHPUnit tests first, and stop if the tests fail. I've been googling this a lot, and it's very hard to find documentation on running unit tests from php, rather than from the command line tool.
For the newest version of PHPUnit, can you do something like:
$unit_tests = new PHPUnit('my_tests_dir');
$passed = $unit_tests->run();
Preferably a solution that doesn't require me to manually specify each test suite.
Figured it out:
$phpunit = new PHPUnit_TextUI_TestRunner;
try {
$test_results = $phpunit->dorun($phpunit->getTest(__DIR__, '', 'Test.php'));
} catch (PHPUnit_Framework_Exception $e) {
print $e->getMessage() . "\n";
die ("Unit tests failed.");
}
Simplest way to do this is by instantiating object of class PHPUnit_TextUI_Command.
So here is an example:
require '/usr/share/php/PHPUnit/Autoload.php';
function dummy($input)
{
return '';
}
//Prevent PHPUnit from outputing anything
ob_start('dummy');
//Run PHPUnit and log results to results.xml in junit format
$command = new PHPUnit_TextUI_Command;
$command->run(array('phpunit', '--log-junit', 'results.xml', 'PHPUnitTest.php'),
true);
ob_end_clean();
This way the results will be logged in results.xml file in junit format that can be parsed. If you need a different format you can check the documentation. Also you can add more options by changing the array passed to run method.
working with PHPUnit 7.5:
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite;
$test = new TestSuite();
$test->addTestSuite(MyTest::class);
$result = $test->run();
and $result object contains lot of usefull data:
$result->errors()
$result->failures
$result->wasSuccessful()
etc...
Solution for PHP7 & phpunit ^7
use PHPUnit\TextUI\Command;
$command = new Command();
$command->run(['phpunit', 'tests']);
Does the same effect as CLI command:
vendor/bin/phpunit --bootstrap vendor/autoload.php tests
It doesn't seem like PHPUnit has any built-in configuration to prevent it from dumping its output directly into the response (at least not as of PHPUnit 5.7).
So, I used ob_start to shunt output to a variable, and set the third argument of doRun to false to prevent PHPUnit from halting the script:
<?php
$suite = new PHPUnit_Framework_TestSuite();
$suite->addTestSuite('App\Tests\DatabaseTests');
// Shunt output of PHPUnit to a variable
ob_start();
$runner = new PHPUnit_TextUI_TestRunner;
$runner->doRun($suite, [], false);
$result = ob_get_clean();
// Print the output of PHPUnit wherever you want
print_r($result);
I want to use a local installation of PHPUnit (via composer) to run my tests and display it on screen (acessing /admin/tests for instance). But the only way to run tests I found in the documentation was the command line tool.
Bellow is an hypothetical example of what I'm looking for:
$session = new PHPUnit_TestSession('path/to/folder');
$results = $session->runAll();
echo $results->failuresCount();
// other hipotetical $result->methods...
// maybe $results->dump()
This may be an overkill but you are in for a treat: https://github.com/NSinopoli/VisualPHPUnit :)
EDIT Here is a rudimentary use of PHPUnit using the TextUI_TestRunner
// make sure you have PHPUnit on your path
require_once "PHPUnit/Framework/TestSuite.php";
require_once "PHPUnit/TextUI/TestRunner.php";
$suite = new PHPUnit_Framework_TestSuite();
$suite->addTestSuite('YourTestCase');
// run the test suite with TextUI_TestRunner
PHPUnit_TextUI_TestRunner::run($suite);
The YourTestCase class is a subclass of PHPUnit_Framework_TestCase, which you can read more on how to write at the official website: http://www.phpunit.de/manual/3.2/en/writing-tests-for-phpunit.html
However, I'd also recommend getting a copy of this book: http://www.amazon.com/Advanced-PHP-Programming-George-Schlossnagle/dp/0672325616 The author teaches you quite a few cool tricks, including autoloading tests, etc.