【问题标题】:How to provide a mock entity manager to test a service class?如何提供模拟实体管理器来测试服务类?
【发布时间】:2018-09-13 06:14:01
【问题描述】:

我的 Symfony (3.4) 应用程序中有一个服务类 (OutletScraper)。该类使用实体管理器和 Bazinga 地理编码器包提供的地理编码服务。我已经成功配置了两者,以便我能够从我的服务类中调用它们。每当我需要该服务时,我都会从容器中调用它,以便已经将实体管理器和地理编码器捆绑包注入其中。

在测试时,我知道我可以模拟实体管理器,然后将其提供给我的测试类。当我从容器访问服务类时,如何覆盖传递给构造函数的内容?即,这样我就可以提供模拟实体管理器,而不是注入真实的实体管理器。我尝试手动实例化服务类的对象:

$outletScraper = new OutletScraper(new Provider(), $this->createMock(EntityManagerInterface::class));

但是这样做时出现以下错误:

Error: Cannot instantiate interface Geocoder\Provider\Provider

如何正确实例化这个类?我需要从服务容器中调用它(它设置为私有)吗?感谢任何帮助。

【问题讨论】:

    标签: php symfony service phpunit containers


    【解决方案1】:

    您对实体管理器的模拟工作正常,问题在于地理编码器提供程序。就像EntityManagerInterface一样,Geocoder\Provider\Provider也是一个接口。库维护者只是选择省略后缀。

    这意味着您不能只创建它,而是必须传递一个实现接口的具体类,例如 Geocoder\Provider\GoogleMaps\GoogleMaps,如果您真的想要进行地理编码调用或模拟 Provider。

    如果您想检查您配置的地理编码提供程序是否有效,您可以使用 Symfony 的 WebTestCase 编写功能测试,大致如下所示:

    <?php
    
    namespace AppBundle\Tests\Scraper;
    
    use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
    
    class OutletScraperTest extends WebTestCase
    {
        public function testFindsLocation()
        {
            // This will instantiate your Symfony application in the test environment
            $client = static::createClient();
    
            $container = $client->getContainer();
            // Replace the class name with the service id, if you use artificial service ids like "app.outlet_scraper"
            $scraper = $container->get(OutletScraper::class);
    
            // Call whatever method you want to test on your outlet scraper
            $result = $scraper->someMethod();
    
            // Assert result matches expectations
            $this->assertEquals(..., $result);
        }
    }
    

    但请注意,这将使用您为应用程序配置的OutletScraper,同时具有 实际 依赖项。因此,您的地理编码提供程序将对您使用的任何提供程序进行实际调用,这可能会用完请求,这可能是有限的。您还将使用真正的 Doctrine EntityManager,这意味着您写入数据库的任何内容都会被实际写入。因此,特别是对于数据库,您应该创建一个单独的测试数据库并在您的 app/config/config_test.yaml 中配置它。

    【讨论】:

      【解决方案2】:

      我的建议是,如果您尝试单独测试此服务,您还应该模拟 Geocoder\Provider\Provider。否则,您的测试断言可能会根据您运行它们的时间而产生不同的结果。

      如果您要经常使用这个模拟,您甚至可以创建自己的测试类来实现该接口,这样您就可以自己在测试环境中准备不同的输出。

      【讨论】:

        猜你喜欢
        • 2016-12-15
        • 1970-01-01
        • 2010-09-10
        • 2014-08-16
        • 2022-12-24
        • 2018-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多