如何在 Symfony 中实例化自动装配服务?

How to instantiate autowired services in Symfony?

我想实例化 OrderAbstraction 服务,它需要在测试用例的构造函数中使用实体管理器。

class OrderAbstraction
{
    ...

    /**
     * @var EntityManager
     */
    private $em;

public function __construct(EntityManager $em)
    {
        $this->em = $em;
        ...
    }
}

我已经尝试自动装配 OrderAbstractionTest 并将 OrderAbstraction 和实体管理器作为参数。

class OrderAbstractionTest extends TestCase
{
// tried with constructor and without it
    public function testDays(){
        $order = new OrderAbstraction();
        $order->dateFrom(new \DateTime('2019-08-20 14:00'));
        $order->dateTo(new \DateTime('2019-08-28 14:00'));

        $days = $order->days();
        $this->assertEquals(8, $days);
    }
}

我的 service.yaml,自动装配设置为 true

    App\Service\OrderAbstraction\:
        resource: '../src/Service/OrderAbstraction.php'
        arguments: 
            $em: '@Doctrine\ORM\EntityManager'

    App\Test\OrderAbstraction\:
        resource: '../tests/OrderAbstractionTest.php'
        arguments: 
            $em : '@Doctrine\ORM\EntityManager'

我一直收到这样的信息:

PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function App\Test\OrderAbstractionTest::__construct(), 0 passed in /var/www/html/autocom/bin/.phpunit/phpunit-6.5/src/Framework/TestSuite.php on line 476 and exactly 1 expected in /var/www/html/autocom/tests/OrderAbstractionTest.php:13

如果知道如何将诸如 OrderAbstraction 之类的服务实例化到其他服务、测试,那就太好了。因为大多数我在控制器中做这样的事情:

$order = new OrderAbstraction($this->em);

最终为我工作的是 php unit mock,我的代码现在如下所示:

    public function testDays(){
        $em = $this->getMockBuilder(EntityManager::class)
        ->disableOriginalConstructor()
        ->getMock();

        $order = new OrderAbstraction($em);
        $order->dateFrom(new \DateTime('2019-08-20 14:00'));
        $order->dateTo(new \DateTime('2019-08-28 14:00'));

        $days = $order->days();
        $this->assertEquals(8, $days);
    }

如果自动装配设置为 true,则 services.yml 中不需要任何内容​​。在您的 OrderAbstraction.php 中将 EntityManager 替换为 EntityManagerInterface 以获取在您的服务自动装配时自动注入的 EntityManager 实例。

OrderAbstraction.php

use Doctrine\ORM\EntityManagerInterface;

class OrderAbstraction {

  /**
   * @var EntityManager
   */
  private $em;

  public function __construct(EntityManagerInterface $em)
  {
    $this->em = $em;
    ...
  }
}

编辑

由于这会在基本控制器中按预期工作,因此您不能使用单元测试的构造函数 class 来注入您的服务。根据 Symfony 的 blog :

In Symfony 4.1, tests allow fetching private services by default. In practice, tests based on WebTestCase and KernelTestCase now access to a special container via the static::$container property that allows fetching non-removed private services:

OrderAbstractionTest.php

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use App\Service\OrderAbstraction;

class OrderAbstractionTest extends WebTestCase {

  /**
   * @var OrderAbstraction
   */
  private $order;

  public function testDays() {
    self::bootKernel();
    $this->order = static::$container->get(OrderAbstraction::class);

    $this->order->dateFrom(new \DateTime('2019-08-20 14:00'));
    $this->order->dateTo(new \DateTime('2019-08-28 14:00'));

    $days = $this->order->days();
  }
}

已在 Symfony 4.3 上测试并正常工作
有关 Symfony 3.4 和 4.0 的更多信息,请参阅