I followed the instructions on this page but couldn't get my unit test working.
http://framework.zend.com/manual/2.2/en/tutorials/unittesting.html
My initial code was like this:
<?php
namespace ApplicationTest\Controller;
use Zend\Http\Request;
use Zend\Http\Response;
use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
class IndexControllerTest extends AbstractHttpControllerTestCase {
protected $controller;
protected $request;
protected $response;
protected $routeMatch;
protected $event;
protected $traceError = true;
public function setUp() {
$this->setApplicationConfig(
include '../../../config/application.config.php'
);
parent::setUp();
}
public function testIndexActionCanBeAccessed() {
$this->dispatch('/');
$this->assertResponseStatusCode(200);
}
}
And when I ran phpunit, I got the following error message:
PHPUnit 3.7.21 by Sebastian Bergmann.
Configuration read from /usr/share/php/tool/module/Application/test/phpunit.xml
onDispatch called.
E
Time: 1 second, Memory: 14.50Mb
There was 1 error:
1) ApplicationTest\Controller\IndexControllerTest::testIndexActionCanBeAccessed
Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Zend\Db\Adapter\Adapter
Then I followed the second set of instructions to configure the service manager.
public function testIndexActionCanBeAccessed() {
$albumTableMock = $this->getMockBuilder('User\Model\UserData')
->disableOriginalConstructor()
->getMock();
$albumTableMock->expects($this->once())
->method('getUserSessionArray')
->will($this->returnValue(array()));
$serviceManager = $this->getApplicationServiceLocator();
$serviceManager->setAllowOverride(true);
$serviceManager->setService('User\Model\UserData', $albumTableMock);
$this->dispatch('/');
$this->assertResponseStatusCode(200);
}
And this time, I got the following error:
PHPUnit 3.7.21 by Sebastian Bergmann.
Configuration read from /usr/share/php/tool/module/Application/test/phpunit.xml
onDispatch called.
PHP Fatal error: Call to undefined method Mock_UserData_ae821217::getUserSessionArray() in /usr/share/php/tool/module/User/Module.php on line 95
PHP Stack trace:
PHP 1. {main}() /usr/local/pear/bin/phpunit:0
…
Could someone help me on this please?
We are using Zend Framework 2.2.0.
Thank you so much.
EC
Your mock isn't quite setup right. You don't set any methods for the mock to have and so your expects isn't really being set. You need to create your mock like this:
$albumTableMock = $this->getMockBuilder('User\Model\UserData')
->disableOriginalConstructor()
->setMethods(array('getUserSessionArray')) //ADD this line
->getMock();
Your User\Model\UserData class doesn't exist and so PHPUnit did not create the method to get mocked. And when you ran your tests the function was not defined.
Related
I have a custom command in my symfony project to populate the database with the default data that the application need to work in both dev and prod environments.
For the dev environment I have a fixture script that depends on these default common data.
I'm trying to call my custom Symfony command in the fixture script so that I'm sure to have the required data to properly load my fixtures.
This is my custom command app:db:populate in "pseudo script", just creating a bunch of entities, persit & flush. My custom command works fine when I call it through php bin/console app:db:populate
protected function execute(InputInterface $input, OutputInterface $output)
{
// Creating a bunch of default entities, persist them and flush
$data = new MyDefaultEntity();
// ...
$this->manager->persist($data);
// ...
$this->manager->flush();
}
Then, in my fixture script, I want to call app:db:populate first, because fixtures depends on these data. So I tried to use the Process class to execute my script this way :
public function load(ObjectManager $manager)
{
// Execute the custom command
$cmd = 'php bin/console app:db:populate';
$process = new Process($cmd);
$process->run(function ($type, $buffer) {
if (Process::ERR === $type) {
echo 'ERR > '.$buffer;
} else {
echo 'OUT > '.$buffer;
}
});
// Then load the fixtures !
// ...
}
The custom command seems to execute well until the $this->manager->flush();
I have the following error in my console (Data is obfuscated for the post):
In AbstractMySQLDriver.php line 36:
An exception occurred while executing 'INSERT INTO ....(..., ..., ...) VALUES (?, ?, ?)' with params ["...", "...", "..."]:
SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction
I don't know what to do regarding this error ... Why the command is working normally when used through a classic console call and why it is not working in a Process?
So, the short answer is
Quoting Symfony documentation :
You may have the need to execute some function that is only available in a console command. Usually, you should refactor the command and move some logic into a service that can be reused in the controller.
I ended up making a service class that handles all the app:db:populate logic (read a json file and insert basic app entities in the database). Then I call this service in both app:db:populate execute methods and AppFixtures load methods.
Hope this will help someone.
I use Symfony\Component\Cache\Simple\FilesystemCache;
It works when I $cache->set $cache->get $cache->clear() etc
I don't want to use a custom ttl. I want to clear the cache setted only with console.
But when I do php bin/console cache:clear, it doesn't clear cache I have set before with FilesystemCache.
I have tried to clear every pools with console but it doesn't clear $cache either.
1. Why it happens
Symfony's bin/console cache:clear command clears the cache only from kernel cache dir, which is var/cache/{env} by default.
When you create instance of FilesystemCache, you can provide a path where you want to store your cache as a 3rd parameter. Here's a signature of FilesystemCache constructor
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null)
If you don't provide 3rd parameter it will end up as sys_get_temp_dir().'/symfony-cache', which is /tmp/symfony-cache on Linux.
As you can see it's a different directory and it won't be cleared by cache:clear command.
2. How to fix it
The proper way
You need to create your own data-cache:clear command. It's very simple https://symfony.com/doc/current/console.html
In execute() method of your command you should instantiate your FilesystemCache and call clear() on it. Example:
protected function execute(InputInterface $input, OutputInterface $output)
{
$cache = new FilesystemCache();
$cache->clear();
}
Then you can call php bin/console data-cache:clear from console.
If you decide to switch to some other caching engine in future (Redis, Memcached etc.) you can simply adjust that command to clear that cache.
The wrong way
It will only work if you keep using FilesystemCache and does not
provide fine-grained control of which cache you actually clear.
You can store your cache in kernel.cache_dir by passing a 3rd parameter to FilesystemCache when you instantiate it.
Example:
$cache = new FilesystemCache('', 0, $container->getParameter('kernel.cache_dir').'/data-cache');
or when configured as a service
Symfony\Component\Cache\Simple\FilesystemCache:
arguments:
- ''
- 0
- '%kernel.cache_dir%/data-cache'
This way Symfony's cache:clear command will work for you, but it's not a good idea to store these 2 types of cache in the same place.
If you change some of your project files, you may want to clear only
kernel cache in /var/cache while keeping your data cache intact and
vice versa. That's why I recommend not to use this solution!
It finally works, using AdapterInterface
<?php
namespace Gh\GhBundle\Manager;
use Symfony\Component\Cache\Adapter\AdapterInterface;
class AppManager
{
protected $_rootDir;
protected $_cache;
public function __construct($rootDir, AdapterInterface $cache)
{
$this->_rootDir = $rootDir;
$this->_cache = $cache;
}
/**
*
* Get version of this app
* #return string
*/
public function getVersion()
{
$cache = $this->_cache;
$numVersion = $cache->getItem('stats.num_version');
if (!$numVersion->isHit()) {
$version = !file_exists($this->_rootDir . '/RELEASE.TXT') ? 'dev' : file_get_contents($this->_rootDir . '/RELEASE.TXT');
$numVersion->set($version);
$cache->save($numVersion);
}
return $numVersion->get();
}
/**
*
* Get name of this app
* #return string
*/
public function getName()
{
return 'GH';
}
}
I use symfony and I have installed whiteoctober TCPDF with success.
It works if I use it in a controller, my PDF is generated.
However I want to use it in a command.
So I have a command called "CronInvoicesCommand" in a command folder and of course I have this error:
Attempted to call method "get" on class "OandP\boBundle\Command\CronInvoicesCommand" in C:\wamp\www\OandPlocal\src\OandP\boBundle\Command\CronInvoicesCommand.php line 187. Did you mean to call: "getAliases", "getApplication", "getDefinition", "getDescription", "getHelp", "getHelper", "getHelperSet", "getName", "getNativeDefinition", "getProcessedHelp", "getSynopsis"?
So my question is how can I load all those method in a command.
Thank you se much for your help
you can use a container aware commmand :
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
class MyCommand extends ContainerAwareCommand
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$em = $this->getContainer()->get('doctrine')->getEntityManager();
// ...
Probably you are trying to get a service from a container similar to the controller method get. In a Command you can access to the container with the getContainer() method, so try to substitute something like:
$this->get('service_name');
with
$this->getContainer()->get('service_name');
More info here in the doc.
Hope this help
I make some functional test with Symfony 2 and phpunit.
But i've some trouble with a Service.
Let me explain.
During my run test, i want to use some service used by the application. So i juste set my setUp function for setting the kernel :
static::$kernel = static::createKernel();
static::$kernel->boot();
$this->objectFactory = static::$kernel->getContainer()->get('some.application.objectfactory');
So i've this and in my function i need to used a service that return an object so i call my service like that
$var = $this->objectFactory->getObject($id);
and obviously in my tearDown function i just :
protected function tearDown()
{
$this->client->restart();
unset($this->client, $this->objectFactory);
}
So my problem is when i run a test i've this message :
Symfony\Component\DependencyInjection\Exception\InactiveScopeException: You cannot create a service ("request") of an inactive scope ("request").
And i can't find a way to solve this.
Did someone have any idea ??
My version of Symfony is 2.2.1 and my version of phpunit is 3.7.19
If someone can help me, i could be very happy.
I'm sorry if my English isn't so good.
EDIT
Maybe it could help someone, in the service i used that : :
$request = $this->container->get('request');
It seems to be the reason why it dosen't work, when i remove it, it doesn't say the error, but they still doesn't work.
EDIT
#Cyprian
According to you have change my code for what i want.
So i just add to my service, in the function that i want, the client (Client web test case), and then inside the function i just add this :
if (isset($client)) {
$request = $client->getRequest();
} else {
$request = $this->container->get('request');
}
So in my function where i call the service i've just this :
public function getObject($id)
{
//Get the service from the kernel
$service = static::$kernel->getContainer()->get('service');
$object = $service->getObject($id, $this->client);
}
and it works fine like this
#nifr
Your idea doesn't work for me, but i think your idea wasn't wrong, they just not works in my case
However Thanks for your help, i'm happy i works now, and i expect that post could help someone else
Try get request from the client, not service container:
$request = $this->client->getRequest();
In that way you can also get kernel and/or container:
$kernel = $this->client->getKernel();
$container = $this->client->getContainer();
One more useful tip: kernel from the client is rebooted between each two requests. So, for example if you pass your mock to client's container and do some request, in next request (after the first one) the container will not contain your mock.
There is no request available in phpUnit as long as you don't construct one.
If you want to test a request. create it like this:
use Symfony\Component\HttpFoundation\Request;
protected $request;
public function setUp()
{
// ...
$this->request = new Request();
// ... modify your request acccording to your needs
}
and add/call a setter in your Service using the request.
$service = $this->kernel->getContainer()->get('your_service')
$service->setRequest($this->request);
or create a Functional Test with WebtestCase.
I want to add log output to all test messages.
$this->assertTrue(FALSE, "This assertion is False.". myLog::GetErrors());
I tried extending the PHPUnit_Framework_TestCase::assertThat function with my appended message, but it doesn't seem to have an effect on it. I know the extended PHPUnit_Framework_TestCase works because I have several helper functions (random string generation) in there as well that I use for testing.
Any other thoughts? Could it be a customer listener?
All of the assertions are static methods from PHPUnit_Framework_Assert and cannot be overridden by a subclass of TestCase. You can define your own assertions that call the originals with an amended message, however.
public static function assertTrue($value, $message='') {
PHPUnit_Framework_Assert::assertTrue($value, $message . myLog::GetErrors());
}
All failed tests call onNotSuccessfulTest() with the exception as the only parameter. You could override this method and in some cases add your log errors to the exception's message. Some of the PHPUnit exceptions provide a second description in addition to the error message contained in the exception.
public function onNotSuccessfulTest(Exception $e) {
if ($e instanceof PHPUnit_Framework_ExpectationFailedException) {
$e->setCustomMessage(implode(PHP_EOL,
array($e->getCustomMessage(), myLog::GetErrors())));
}
parent::onNotSuccessfulTest($e);
}
Update: As Gregory Lo noted in a comment below, setCustomMessage() and getCustomMessage() were removed in PHPUnit 3.6. :(
In recent PHPUnit Versions it is not necessary anymore.
When you specify the error parameter in an $this->assertXXXX() it preceeds PHPUnit's original message.
Screenshot: