如何提供模拟实体管理器来测试服务类?



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

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

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

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

Error: Cannot instantiate interface GeocoderProviderProvider

如何正确实例化此类?是否需要从服务容器调用它(其设置为私有(?感谢任何帮助。

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

这意味着您不能只创建它,而是必须传递一个实现接口的具体类,例如GeocoderProviderGoogleMapsGoogleMaps,如果您实际上也想进行地理编码调用或模拟提供程序。

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

<?php
namespace AppBundleTestsScraper;
use SymfonyBundleFrameworkBundleTestWebTestCase;
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中进行配置。

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

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

最新更新