PHP symfony4:在 KernelTestCase 中为命令注入依赖项

PHP symfony4: Dependency injection inside KernelTestCase for command

您好,我正在尝试为 symfony4 控制台命令创建单元测试,但我无法正确注入依赖项。我是 symfony4 的新手,所以也许这对你们来说是一个基本问题。

我的单元测试是这样的:

<?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);
    }
}

我的问题是我遇到这样的注入错误:

ArgumentCountError: Too few arguments to function App\Tests\Command\ExeculteSalesTaskCommandTest::testExecute(), 0 passed and exactly 2 expected

更新: 当我从容器中提取依赖项时,出现这种错误:

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.

如何正确注入必要的依赖项,以便创建 ExecuteSalesTaskCommand 的实例?

好吧,我发现问题出在我尝试手动加载依赖项。像这样使用自动装配:

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
}

您需要从内核容器中获取命令本身。现在可以了。

我也遇到过类似的问题。但以下对我有用。我不认为你需要向应用程序添加命令并再次找到它?请找到以下解决方案。它可能会帮助别人。

<?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;
    }

}

测试用例

// 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);
    }
}

测试结果运行

#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)

我正在使用以下 Sf4 版本

 -------------------- --------------------------------------
  Symfony
 -------------------- --------------------------------------
  Version              4.1.7

服务定义及其默认私有

#config/services.yml
    App\Service\FeedGenerator:
        arguments:
            $feeds: '%feed_generator%'

我认为您不需要再次自动装配。