I'm trying to test my RoomRepository with PHPUnit and Symfony 4. I installed symfony/phpunit-bridge using composer. I created a simple entity called Room with one id and name attributs and a repository method to get a Room by its id.
public function get(int $id): ?Room
{
/** #var Room $room */
$room = $this->findOneBy(['id' => $id]);
return $room;
}
My test is quite simple as you can see :
public function testGet(): void
{
/** #var RoomRepository $repository */
$repository = $this->em->getRepository(Room::class);
$room = $repository->get(1);
$this->assertCount(1, $room);
}
I am new with test and I don't know if it's the right way to proceed. I followed the Symfony documentation.
So, when I execute the following command :
./vendor/bin/simple-phpunit
I am getting this error :
Doctrine\DBAL\Exception\ConnectionException: An exception occurred in driver: SQLSTATE[HY000] [2002] No such file or directory
I am pretty sure this is a commun mistake and very easy to fix...
Furthermore, I wrote other simple asserts that worked very well. I don't think it's about PHPUnit configuration.
Here some informations about my env :
PHP 7.1
Symfony4.0.5
PHPUnit 5.7.27
Docker with Laradock (containers : mysql, apache2, workspace)
Thanks guys for reading my post and have a nice day :)
I had the same problem – I just forgot to add the database url to the phpunit.xml.dist file. You have to add:
<phpunit ...>
<php>
...
<env name="DATABASE_URL" value="mysql://username:password#server:port/database" />
...
</php>
...
</phpunit>
Of course with your own credentials instead of the placeholders.
I want to test a class by checking the real database data after function is executed.
I do not understand, how can I inject services which I need, for example some repository class.
So far I have written this:
namespace Tests\integration\Service\JourneyRunner\EmailConditionCheck;
use PHPUnit_Framework_TestCase;
use NG\Model\Journey\EmailConditionCheckRepositoryInterface;
class EmailConditionCheckServiceTest extends PHPUnit_Framework_TestCase
{
private $emailConditionCheckQueueRepository;
public function __construct(
EmailConditionCheckQueueRepositoryInterface $emailConditionCheckQueueRepository
) {
$this->emailConditionCheckQueueRepository;
parent::__construct();
}
public function testPrepareEmailContentForSending()
{
echo 'aaa';
$this->assertEquals(1, 1);
}
}
I added the test service to services.xml
<parameter key="tests.integration.service.journey_runner.email_condition_check.email_condition_check_service_test.class">tests\integration\Service\JourneyRunner\EmailConditionCheck\EmailConditionCheckServiceTest</parameter>
<service id="tests.integration.service.journey_runner.email_condition_check.email_condition_check_service_test" class="%tests.integration.service.journey_runner.email_condition_check.email_condition_check_service_test%">
<argument type="service" id="ng.infrastructure.persistence.time_trigger_queue_repository" />
</service>
I know that argument is wrong currently, but from the error I see that it does not get even the wrong argument - it gets nothing.
PHP Fatal error: Uncaught TypeError: Argument 1 passed to Tests\integration\Service\JourneyRunner\EmailConditionCheck\EmailConditionCheckServiceTest::__construct() must be an instance of Tests\integration\Service\JourneyRunner\EmailConditionCheck\EmailConditionCheckQueueRepositoryInterface, none given, called in /var/www/api.notification.guru/ng-api-service/vendor/phpunit/phpunit/src/Framework/TestSuite.php on line 475 and defined in /var/www/api.notification.guru/ng-api-service/tests/integration/Service/JourneyRunner/EmailConditionCheck/EmailConditionCheckServiceTest.php:12
I tried to search for info, but I cannot find.
Found out how, not inject, but geting a container gives result I want:
<?php
namespace Tests\integration\Service\JourneyRunner\EmailConditionCheck;
use PHPUnit_Framework_TestCase;
use NG\Model\Journey\EmailConditionCheckRepositoryInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use NG\Model\Uuid;
class EmailConditionCheckServiceTest extends KernelTestCase
{
private $emailConditionCheckQueueRepository;
protected function setUp()
{
self::bootKernel();
$this->container = static::$kernel->getContainer();
$this->emailConditionCheckQueueRepository = $this->container->get('ng.infrastructure.persistence.email_condition_check_repository');
}
public function testPrepareEmailContentForSending()
{
$this->emailConditionCheckQueueRepository->get(Uuid::fromString('1'));
$this->assertEquals(1, 1);
}
}
Also needed to create phpunit.xml - set the app directory. App directory is the one where AppKernel.php lies in your project as I understood.
<?xml version="1.0" ?>
<phpunit>
<php>
<server name="KERNEL_DIR" value="app/" />
</php>
</phpunit>
And pass to phpunit command a parameter
--configuration=phpunit.xml
I created a new Class in src/CollaboratorsBundle/Command, named it GenerateFormRemindersCommand.php and put the following code in it:
<?php
namespace Myproject\CollaboratorsBundle\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
class GenerateFormRemindersCommand extends ContainerAwareCommand{
protected function configure() {
$this->setName("generate:formReminders")
->setDescription('Send reminders by email to all collaborators with unanswered forms');
}
protected function execute(InputInterface $input, OutputInterface $output) {
//some code
}
}
Upon execution, i get the following message :
$ php app/console generate:formReminders
[InvalidArgumentException]
Command "generate:formReminders" is not defined.
I've checked in my AppKernel.php file that my bundle was registered in it and it was.
I've tried adding parent:configure(); to the configure method but without any results.
I've created a few other custom commands that work correctly. I don't get what I am doing wrong in this case. Do you ?
Thanks in advance
I had the same trouble because I named file without "Command" suffix.
You have to name your file as 'GenerateFormRemindersCommand.php'.
I had the same error. The problem I had was I implemented the constructor to initialize a repository field instead of the initialize() method.
If you configure your command as a service (for dependency injection or other purposes) and the command has a custom constructor - you shouldn't forget to tag it with console.command, e.g.
your_service:
class: Your\Class
tags:
- "console.command"
You have not placed your file at the correct location.
Looking over your code and the namespace used as well as you have already mentioned, that you have placed the file inside src/CollaboratorsBundle/Command. While it must be placed inside src/Myproject/CollaboratorsBundle/Command.
Same problem but because I forgot to extends ContainerAwareCommand
execute
bin/console cache:clear
I've created a fixtures class inside my bundle's DataFixtures/ORM folder. The actual class looks like this:
use Doctrine\Common\DataFixtures\FixtureInterface,
Company\ShoppingBundle\Entity\Category;
class CategoryFixtures implements FixtureInterface
{
public function load($em)
{
$category1 = new Category()->setName("category1");
$category2 = new Category()->setName("category2");
$em->persist($category1);
$em->persist($category2);
$em->flush();
}
}
I'm not using the AbstractFixture base class, since I don't need references. I've also tried specifying the fixtures path when running the doctrine:fixtures:load console command. I'm following the official docs here.
Nothing wrong with the file naming, or my configuration: I simply forgot to put
<?php
at the top of my file :-D
I created a new Class in src/MaintenanceBundle/Command, named it GreetCommand.php and put the following code in it:
<?php
namespace SK2\MaintenanceBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class GreetCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
->setName('maintenance:greet')
->setDescription('Greet someone')
->addArgument('name', InputArgument::OPTIONAL, 'Who do you want to greet?')
->addOption('yell', null, InputOption::VALUE_NONE, 'If set, the task will yell in uppercase letters')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
if ($name) {
$text = 'Hello '.$name;
} else {
$text = 'Hello';
}
if ($input->getOption('yell')) {
$text = strtoupper($text);
}
$output->writeln($text);
}
}
?>
And tried to call it via
app/console maintenance:greet Fabien
But i always get the following error:
[InvalidArgumentException]
There are no commands defined in the "maintenance" namespace.
Any ideas?
I had this problem, and it was because the name of my PHP class and file didn't end with Command.
Symfony will automatically register commands which end with Command and are in the Command directory of a bundle. If you'd like to manually register your command, this cookbook entry may help: http://symfony.com/doc/current/cookbook/console/commands_as_services.html
I had a similar problem and figured out another possible solution:
If you override the default __construct method the Command will not be auto-registered by Symfony, so you have to either take the service approach as mentioned earlier or remove the __construct override and make that init step in the execute method or in the configure method.
Does actually anyone know a good best practice how to do init "stuff" in Symfony commands?
It took me a moment to figure this out.
I figured out why it was not working: I simply forgot to register the Bundle in the AppKernel.php. However, the other proposed answers are relevant and might be helpful to resolve other situations!
By convention: the commands files need to reside in a bundle's command directory and have a name ending with Command.
in AppKernel.php
public function registerBundles()
{
$bundles = [
...
new MaintenanceBundle\MaintenanceBundle(),
];
return $bundles;
}
In addition to MonocroM's answer, I had the same issue with my command and was silently ignored by Symfony only because my command's constructor had 1 required argument.
I just removed it and call the parent __construct() method (Symfony 2.7) and it worked well ;)
If you are over-riding the command constructor and are using lazy-loading/autowiring, then your commands will not be automatically registered. To fix this you can add a $defaultName variable:
class SunshineCommand extends Command
{
protected static $defaultName = 'app:sunshine';
// ...
}
Link to the Symfony docs.
I think you have to call parent::configure() in your configure method
I had this same error when I tried to test my command execution with PHPUnit.
This was due to a wrong class import :
use Symfony\Component\Console\Application;
should be
use Symfony\Bundle\FrameworkBundle\Console\Application;
cf. Other stack thread
In my case it was complaining about the "workflow" namespace although the WorkflowDumpCommand was correctly provided by the framework.
However, it was not available to run because I have not defined any workflows so the isEnabled() method of the command returned false.
I tried to use a service passed via constructor inside the configure method:
class SomeCommand extends Command {
private $service;
public function __construct(SomeService $service) {
$this->service = $service;
}
protected function configure(): void {
$this->service->doSomething(); // DOES NOT WORK
}
}
Symfony uses Autoconfiguration that automatically inject dependencies into your services and register your services as Command, event,....
So first just make sure that you have services.yaml in your config folder. with autoconfigure:true.
this is the default setting
Then Make sure That All your files are exactly the same name as Your Class.
so if you have SimpleClass your file must be SimpleClass.php
If you have a problem because of a __constructor,
go to services.yml and add something like this:
app.email_handler_command:
class: AppBundle\Command\EmailHandlerCommand
arguments:
- '#doctrine.orm.entity_manager'
- '#app.email_handler_service'
tags:
- { name: console.command }
For newer Symfony-Version (5+) commands must be registered as services.
What I do frequently forget while setting it up, is to tag it properly:
<service id="someServiceCommand">
<tag name="console.command"/>
</service>
Without this litte adaptation, your command name will not be displayed and therefore not accessible.