【问题标题】:php+symfony - phpunit test - Cannot instantiate interface errorphp+symfony - phpunit 测试 - 无法实例化接口错误
【发布时间】:2021-03-20 16:27:51
【问题描述】:

我正在尝试编写我的第一个 php 单元测试。但我得到下一个错误:

错误:无法实例化接口 Doctrine\Persistence\ManagerRegistry

这是什么原因,我该如何解决?我正在使用 PHP + Symfony。 这是一个服务控制器的代码示例,我在其中使用了函数 add:

class OrdersService
{
    protected $ordersRepository;
    protected $manager;
    protected $router;

    public function __construct(OrdersRepository $ordersRepository, EntityManagerInterface $manager, RouterInterface $router)
    {
        $this->ordersRepository = $ordersRepository;
        $this->manager = $manager;
        $this->router = $router;
    }

    public function add($shoesid, $sizeid) {
        $cart = $this->session->get('cart', []);

        if(!empty($cart[$shoesid][$sizeid])) {
            if(($cart[$shoesid][$sizeid]) < 3){
                $cart[$shoesid][$sizeid]++;
            } else {
                $cart[$shoesid][$sizeid] = 3;
            }
            
        } else {
            $cart[$shoesid][$sizeid] = 1;
        }
        
        $this->session->set('cart', $cart);
    }
}

这是测试的代码:

class OrderTest extends TestCase
{
    public function addShoes3()
    {
        $registry = new ManagerRegistry();
        $ordersRepository = new OrdersRepository($registry);
        $router = new RouterInterface();

        $ordersService = new OrdersService($ordersRepository, $manager, $router);
        $actual = $ordersService->add(40002, 400);
        $expected = $ordersService->add(40002, 400);

        $this->assertEquals($expected, $actual);
    }
} 

【问题讨论】:

  • 嗯,你正在做的正是错误告诉你的——试图实例化一个接口。接口不是类,你不能用它们制造对象。

标签: php unit-testing symfony doctrine phpunit


【解决方案1】:

正如错误消息告诉您的那样:在您的测试中,您尝试使用new ManagerRegistry() 创建一个接口实例。但是你不能实例化接口。

在您的OrdersService 中,您拥有这些服务,因为您将它们添加为构造函数参数,并且 symfony 的依赖注入组件会处理它们的创建。

在您的单元测试中,您通常不希望拥有所有这些依赖项的真实实例(以及它们自己的所有依赖项等)。相反,您想要一个模拟版本。一个模拟,就像它是真实的对象一样。因此,您需要为所有依赖项创建模拟并将它们添加到您的测试中的OrdersService

public function addShoes3()
{
    $registry = $this->createMock(ManagerRegistry::class);
    $ordersRepository = $this->createMock(OrdersRepository::class);
    $router = $this->createMock(RouterInterface::class);

    $ordersService = new OrdersService($ordersRepository, $manager, $router);
    $actual = $ordersService->add(40002, 400);
    $expected = $ordersService->add(40002, 400);

    $this->assertEquals($expected, $actual);
}

【讨论】:

  • 谢谢它的工作,但现在当我尝试时: $actual = $ordersService->add(40003, 410); $expected = $ordersService->add(40002, 400); $this->assertEquals($expected, $actual);我知道测试成功通过(OK - 1 test, 1 assertion)。为什么会这样?
  • @Silentcow 那是另一个问题,可能应该在一个单独的问题中解决。但无论如何简短的回答:你的测试并没有真正测试任何东西。您的 ordersService-&gt;add() 返回 null。所以对add() 的任何两次调用都会返回相同的结果。
【解决方案2】:

WebTestCase

应用程序测试是 PHP 文件,通常位于应用程序的 tests/Controller/ 目录中,它告诉 Symfony 我们需要必要的工具来与我们的应用程序通信,就好像我们通过 HTTP 进行通信一样。

内核测试

用于从依赖注入容器中获取服务,它可以帮助您在测试中创建和启动内核

这就是我推荐你使用 KernelTestCase 的原因

use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class OrderTest extends KernelTestCase
{
private $registry;

protected function setUp(): void
{
   self::bootKernel();
   $this->registry = self::getContainer()->get('Doctrine\Persistence\ManagerRegistry');
}

public function addShoes3()
{
     $registry = $this->registry;
    //continue
}
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-27
    • 2015-01-14
    • 2016-05-22
    • 1970-01-01
    • 2018-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多