Reputation: 4265
Hello I'm trying to create a unit-test for a symfony4 console command but I can't inject the dependencies correctly. I'm very new to symfony4 so maybe this is a basic question for you guys.
My unit test looks like this:
<?php
namespace App\Tests\Command;
use App\Command\ExecuteSalesTaskCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Tester\CommandTester;
use Psr\Log\LoggerInterface;
use App\Repository\TaskRepository;
class ExeculteSalesTaskCommandTest extends KernelTestCase
{
/**
* @param LoggerInterface $logger
* @param TaskRepository $taskRepository
*/
public function testExecute(LoggerInterface $logger, TaskRepository $taskRepository)
{
$kernel = self::bootKernel();
$application = new Application($kernel);
$application->add(new ExecuteSalesTaskCommand($logger,$taskRepository));
# UPDATED
$logger = self::$kernel->getContainer()->get(LoggerInterface::class);
$taskRepository = self::$kernel->getContainer()->get(TaskRepository::class);
$command = $application->find('app:execute-sales-task');
$commandTester = new CommandTester($command);
$commandTester->execute(
[
'command' => $command->getName(),
]
);
// the output of the command in the console
$output = $commandTester->getDisplay();
$this->assertContains('Execute sales resulted: ', $output);
}
}
My problem is that I get injection errors like this:
ArgumentCountError: Too few arguments to function App\Tests\Command\ExeculteSalesTaskCommandTest::testExecute(), 0 passed and exactly 2 expected
UPDATE: When I fetch the dependencies out of the container I get this kind of error:
There was 1 error:
1) App\Tests\Command\ExeculteSalesTaskCommandTest::testExecute Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: The "Psr\Log\LoggerInterface" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.
How can I inject the necessary dependencies correctly, so I can create an instance of the ExecuteSalesTaskCommand?
Upvotes: 2
Views: 2881
Reputation: 1022
I was also encountered similar issue. But following worked for me. I don't think you need to add command to the application and again to find it? Please find following solution. It might help others.
<?php
// BaseCommandTester.php
/**
* This is basis for the writing tests, that will cover commands
*
*/
namespace App\Tests\Base;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Dotenv\Dotenv;
class BaseCommandTester extends KernelTestCase
{
/**
* @var
*/
private $application;
/**
* to set test environment and initiate application kernel
*/
public function setUp()
{
/**
* get test env
*/
$dotenv = new Dotenv();
$dotenv->load('/var/www/.env.test');
/**
* boot kernel
*/
$kernel = self::bootKernel();
$this->application = new Application($kernel);
parent::setUp();
}
/**
* @return mixed
*/
public function getApplication()
{
return $this->application;
}
/**
* @param mixed $application
*/
public function setApplication($application)
{
$this->application = $application;
}
}
Test Case
// FeedUpdaterCommandTest.php
<?php
namespace App\Tests\Command;
use App\Tests\Base\BaseCommandTester;
use Symfony\Component\Console\Tester\CommandTester;
class FeedUpdaterCommandTest extends BaseCommandTester
{
/**
* test to update all feeds
*/
public function testExecuteUpdateAll() {
/**
* init command tester and executre
*/
$commandName = 'app:feedUpdater';
$expectedResult = '[OK] Update Success Feed Type : All';
$command = $this->getApplication()->find($commandName);
$commandTester = new CommandTester($command);
$commandTester->execute(array(
'command' => $command->getName()
));
/**
* get result and compare output
*/
$result = trim($commandTester->getDisplay());
$this->assertEquals($result, $expectedResult);
}
}
Result of Test run
#Run tests
root@xxx:/var/www# bin/phpunit tests/Command
#!/usr/bin/env php
PHPUnit 6.5.13 by Sebastian Bergmann and contributors.
Testing tests/Command
2018-11-28T07:47:39+00:00 [alert] Successful update of popularProducts Feeds!
2018-11-28T07:47:39+00:00 [alert] Successful update of topVouchers Feeds!
. 1 / 1 (100%)
Time: 1.44 seconds, Memory: 12.00MB
OK (1 test, 1 assertion)
I am using following Sf4 version
-------------------- --------------------------------------
Symfony
-------------------- --------------------------------------
Version 4.1.7
Service Defination and its by default private
#config/services.yml
App\Service\FeedGenerator:
arguments:
$feeds: '%feed_generator%'
I don't think you need to autowire again.
Upvotes: 1
Reputation: 4265
Well I found out that the issue was that I tried to load the dependencies manually. Use the autowiring instead like this:
public function testExecute()
{
$dotenv = new Dotenv();
$dotenv->load(__DIR__.'/.env.test');
$kernel = self::bootKernel();
$application = new Application($kernel);
$executeSalesCommand = self::$kernel->getContainer()->get(
'console.command.public_alias.App\Command\ExecuteSalesTaskCommand'
);
$application->add($executeSalesCommand);
$command = $application->find('app:execute-sales-task');
$commandTester = new CommandTester($command);
$commandTester->execute(
[
'command' => $command->getName(),
]
);
// the output of the command in the console
$output = $commandTester->getDisplay();
// do your asserting stuff
}
You need to get the command itself from the kernel container. Now it works.
Upvotes: 1