在Symfony 3.3中对使用EntityManagerInterface的服务进行单元测试

5cg8jx4n  于 2023-06-24  发布在  其他
关注(0)|答案(3)|浏览(101)

我有一个使用EntityManagerInterface的服务:

class DocFinderService
{
   protected $em;

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

  public function findDocs($specialtyCodes, $city, $state, $zip)
  {...}

如何使用PHPUnit测试服务,具体地说,如何从测试函数传递 EntityManagerInterface 参数?

bjg7j2ky

bjg7j2ky1#

当你写一个单元测试,我的意思是真正的UNIT测试(你也可以使用PHPUnit进行功能测试),你必须总是问自己你想要测试什么。
你想测试EntityManager吗?答案是否定的。更重要的是-即使EntityManager由于某些奇妙的原因停止正常工作,您的测试也应该通过。
所以你必须使用EntityManager的mock。请查看文档了解更多详情https://phpunit.readthedocs.io/en/latest/test-doubles.html#mock-objects
mock的内容取决于findDocs方法的代码。只要它是 find 函数,我认为你必须测试findDocs返回一些数据,如果ORM层能够找到一些东西,如果ORM层没有找到数据,则返回null(或空数组或抛出Exception)。

class DocFinderService extends TestCase {

        public function testFound() {
            /** @var EntityManagerInterface | MockObject $entityManager */
            $entityManager = $this->createMock(EntityManagerInterface::class);

            /** @var ObjectRepository | MockObject $repo */
            $repo = $this->createMock(ObjectRepository::class);
            $repo->expects($this->once())->method('findBy')->willReturn([new DocEntity('doc_id_1'), new DocEntity('doc_id_2')]);
            $entityManager->expects($this->once())->method('getRepository')->willReturn($repo);

            $docFinder = new DocFinderService($entityManager);
            $result = $docFinder->findDocs('SOME_SPECILAITY_CODE', 'City', 'State', 'ZIP');
            $this->assertTrue(is_array($result));
            $this->assertCount(2, $result);
        }

        public function testNotFound() {
            /** @var EntityManagerInterface | MockObject $entityManager */
            $entityManager = $this->createMock(EntityManagerInterface::class);

            /** @var ObjectRepository | MockObject $repo */
            $repo = $this->createMock(ObjectRepository::class);
            $repo->expects($this->once())->method('findBy')->willReturn(null);
            $entityManager->expects($this->once())->method('getRepository')->willReturn($repo);

            $docFinder = new DocFinderService($entityManager);
            $result = $docFinder->findDocs('SOME_SPECILAITY_CODE', 'City', 'State', 'ZIP');
            $this->assertNull(result);
        }
    }

我还添加了ObjectRepository的mock,假设在您的代码中,您将使用它来获取元素。您可以使用QueryBuilder或其他方式来实现相同的目的。
这完全是关于“真正的”单元测试。如果你想在一些测试环境中使用真实的的EntityManager,在这种情况下,你需要初始化你的应用程序或应用程序的某些部分,这些部分影响ORM层测试环境参数。但这是另一个很长的故事

brccelvz

brccelvz2#

您可以像模拟其他任何东西一样模拟它,并像测试其他对象一样测试对它的任何调用。
例如,这里有一个片段,我使用了一个名为Mockery的库(别名为'm::'),并告诉它我希望应该调用flush()

$em = m::mock(EntityManagerInterface::class);
$em->shouldReceive('flush');

$this->whc = new WebhookController($this->log, $this->eventDispatcher, $em);

你的mock/stub需要有多复杂取决于你的代码,以及它的可测试性。

0aydgbwb

0aydgbwb3#

我真的不明白你想做什么,但是如果你想做的是在phpunit中加载所有你需要的依赖注入类,测试代码应该是这样的:

//make sure your test extends of 'KernelTestCase' and not 'TestCase'
class MyTest extends KernelTestCase
{
  /**
   * @var DocFinderService
   */
  private $docFinderService;

  protected function setUp(): void
  {
    // Initializing symfony's kernel
    self::bootKernel();

    // getting the application
    $application = new \Symfony\Bundle\FrameworkBundle\Console\Application(self::$kernel);
    $this->docFinderService = self::$container->get(DocFinderService::class);
  }

  public function testExecute(): void
  {
     // here you can use $docFinderService
     $this->findDocs(...);
  }
}

相关问题