php 如何在 symfony2 中测试服务?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17798143/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I test a service in symfony2?
提问by Dr.Knowitall
Since I'm working with services, this question may end up being an issue with dependency-injection in symfony. Currently I'm trying to test one simple feature in my service via phpunit test and I keep getting the following error:
由于我正在使用服务,因此这个问题最终可能会成为 symfony 中的依赖注入问题。目前,我正在尝试通过 phpunit test 测试我的服务中的一项简单功能,但我不断收到以下错误:
PHP Catchable fatal error: Argument 1 passed to Caremonk\MainSiteBundle\Tests\Services\GeoTest::__construct() must be an instance of Caremonk\MainSiteBundle\Tests\Services\Geo, none given, called in /usr/share/nginx/html/caremonk/vendor/phpunit/phpunit/PHPUnit/Framework/TestSuite.php on line 473 and defined in /usr/share/nginx/html/caremonk/src/Caremonk/MainSiteBundle/Tests/Services/GeoTest.php on line 14
From the error, it is obvious that I am trying create an instance of my service and the correct argument is not being passed, so bellow is my services.yml file:
从错误中,很明显我正在尝试创建我的服务的一个实例,但没有传递正确的参数,所以下面是我的 services.yml 文件:
#src/Caremonk/MainSiteBundle/Resources/config/services.yml
parameters:
caremonk_main_site.geo.class: Caremonk\MainSiteBundle\Services\Geo
caremonk_main_site.geo_test.class: Caremonk\MainSiteBundle\Tests\Services\GeoTest
services:
geo:
class: %caremonk_main_site.geo.class%
arguments: []
geo_test:
class: %caremonk_main_site.geo_test.class%
arguments: ["@geo"]
Bellow is my service that I've built:
Bellow 是我构建的服务:
<?php
//src/Caremonk/MainSiteBundle/Services/Geo.php
namespace Caremonk\MainSiteBundle\Services;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class Geo extends Controller
{
public $pi80;
public $latRad;
public $lngRad;
public function __construct()
{
$this->pi80 = M_PI / 180;
}
// Takes longitude and latitude and converts them into their respective radians
// We also set our class properties to these values
public function setCoordinates($lat,$lng)
{
$this->latRad = $lat * $this->pi80;
$this->lngRad = $lng * $this->pi80;
}
public function distance($lat2, $lng2, $miles = true)
{
$lat1 = $this->latRad;
$lng1 = $this->lngRad;
$lat2 *= $pi80;
$lng2 *= $pi80;
$r = 6372.797; // mean radius of Earth in km
$dlat = ($lat2 - $lat1)/2;
$dlng = ($lng2 - $lng1)/2;
$a = sin($dlat) * sin($dlat) + cos($lat1) * cos($lat2) * sin($dlng) * sin($dlng);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$km = $r * $c;
return ($miles ? ($km * 0.621371192) : $km);
}
// This function returns the minimum latitude in radians
public function min_lat($lat,$lng,$dis)
{
$dis /= .62137119;
$ratio = $dis/6372.797;
return asin(sin($lat)*cos($ratio) + cos($lat)*sin($ratio)*cos(M_PI));
}
// This function returns the max latitude in radians
public function max_lat($lat,$lng,$dis)
{
$dis /= .62137119;
$ratio = $dis/6372.797;
return asin(sin($lat)*cos($ratio) + cos($lat)*sin($ratio)*cos(0));
}
// This function returns max longitude in radians
public function max_lon($lat,$lng,$dis)
{
$dis /= .62137119;
$ratio = $dis/6372.797;
return $lng + atan2(sin(M_PI/2)*sin($ratio)*cos($lat),cos($ratio)-sin($lat)*sin($lat));
}
// This function returns min longitude in radians
public function min_lon($lat,$lng,$dis)
{
$dis /= .62137119;
$ratio = $dis/6372.797;
return $lng + atan2(sin(M_PI*1.5)*sin($ratio)*cos($lat),cos($ratio)-sin($lat)*sin($lat));
}
}
My test file is shown here:
我的测试文件显示在这里:
<?php
//src/Caremonk/MainSiteBundle/Tests/Services/GeoTest.php
namespace Caremonk\MainSiteBundle\Tests\Services;
use Caremonk\MainSiteBundle\Services;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class GeoTest extends WebTestCase
{
public $geo;
public function __construct(Geo $geo)
{
$this->geo = $geo;
}
public function testSetCoordinates()
{
$this->geo->setCoordinates(4,5);
//print $geoService->distance(6,5);
}
}
Lastly, my services are registered bellow in the app/config.yml file:
最后,我的服务在 app/config.yml 文件中注册如下:
imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: "@CaremonkMainSiteBundle/Resources/config/services.yml" }
# Other config.yml stuff
I don't get dependency that well and I'm hoping that my interpretation of it as shown in this post is close to what symfony had in mind. Please let me know what I'm doing wrong so I can test my service.
我没有那么好地获得依赖,我希望我在这篇文章中对它的解释与 symfony 的想法接近。请让我知道我做错了什么,以便我可以测试我的服务。
回答by Paul Dixon
In your test case, you're not going to get anything in your constructor - you can set up the object you want to test in a setupBeforeClass or setup method, e.g.
在你的测试用例中,你不会在你的构造函数中得到任何东西——你可以在 setupBeforeClass 或 setup 方法中设置你想要测试的对象,例如
public static function setUpBeforeClass()
{
//start the symfony kernel
$kernel = static::createKernel();
$kernel->boot();
//get the DI container
self::$container = $kernel->getContainer();
//now we can instantiate our service (if you want a fresh one for
//each test method, do this in setUp() instead
self::$geo = self::$container->get('geo');
}
(Note also you don't need to set up your test classes as services either, so you can remove your geo_test service from services.yml)
(另请注意,您也不需要将测试类设置为服务,因此您可以从 services.yml 中删除您的 geo_test 服务)
Once you've done that, you should be able to run your test case with something like
完成后,您应该能够使用类似的东西运行您的测试用例
cd /root/of/project
phpunit -c app src/Caremonk/MainSiteBundle/Tests/Services/GeoTest.php
回答by Rob
If your are not going to test controllers(with client, because controller called like this will use a new container) your test class should just extend KernelTestCase (Symfony\Bundle\FrameworkBundle\Test). To boot the kernel & get services you can do sth like this in your test setup:
如果您不打算测试控制器(使用客户端,因为这样调用的控制器将使用新容器)您的测试类应该只扩展 KernelTestCase (Symfony\Bundle\FrameworkBundle\Test)。要启动内核并获取服务,您可以在测试设置中执行以下操作:
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class MyTest extends KernelTestCase
{
public function setUp()
{
$kernel = self::bootKernel();
$this->geo = $kernel->getContainer()->get('geo');
}
...
}
More info: http://symfony.com/doc/current/testing/doctrine.html
更多信息:http: //symfony.com/doc/current/testing/doctrine.html
Notes:
笔记:
- To have fresh kernel & services for each test I recommend to use the
setUp
method instead ofsetUpBeforeClass
(like in the accepted answer). - The kernel is always accessible via
static::$kernel
(after booting). - Also works in symfony 3 & 4.
- 要为每个测试提供新的内核和服务,我建议使用该
setUp
方法而不是setUpBeforeClass
(就像在接受的答案中一样)。 - 内核始终可通过
static::$kernel
(启动后)访问。 - 也适用于 symfony 3 & 4。