Поскольку я работаю с сервисами, этот вопрос может оказаться проблемой с вложением зависимостей в symfony. В настоящее время я пытаюсь проверить одну простую функцию в моем сервисе с помощью phpunit-теста, и я продолжаю получать следующую ошибку:
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
Из ошибки очевидно, что я пытаюсь создать экземпляр моей службы, и правильный аргумент не передается, так что это мой файл 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 – моя служба, которую я создал:
<?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)); } }
Мой тестовый файл показан здесь:
<?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); } }
Наконец, мои службы зарегистрированы ниже в файле app / config.yml:
imports: - { resource: parameters.yml } - { resource: security.yml } - { resource: "@CaremonkMainSiteBundle/Resources/config/services.yml" } # Other config.yml stuff
Я не получаю зависимость, и я надеюсь, что моя интерпретация этого, как показано в этом сообщении, близка к тому, что имел в виду symfony. Пожалуйста, дайте мне знать, что я делаю неправильно, поэтому я могу проверить свое обслуживание.
В тестовом примере вы не получите ничего в своем конструкторе – вы можете настроить объект, который хотите протестировать, в методе 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'); }
(Обратите внимание, что вам также не нужно настраивать свои тестовые классы как сервисы, поэтому вы можете удалить свою службу geo_test с services.yml)
Как только вы это сделаете, вы сможете запустить тестовый пример с чем-то вроде
cd /root/of/project phpunit -c app src/Caremonk/MainSiteBundle/Tests/Services/GeoTest.php
Если вы не собираетесь тестировать контроллеры (с клиентом), ваш тестовый класс должен просто расширить KernelTestCase (Symfony \ Bundle \ FrameworkBundle \ Test). Чтобы загрузить ядро и получить службы, добавьте sth, как это, в свою тестовую настройку:
public function setUp() { self::bootKernel(); $this->geo = static::$kernel->getContainer()->get('geo'); }
Дополнительные документы: http://symfony.com/doc/current/cookbook/testing/doctrine.html
Если вы не хотите делать тесты в приложении, но в автономном комплекте, я бы предложил вам взглянуть на очень подробный ответ на этот вопрос .