Подтвердить что ты не робот

Как проверить службу в symfony2?

Поскольку я работаю с сервисами, этот вопрос может оказаться проблемой с вложением зависимостей в 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. Пожалуйста, дайте мне знать, что я делаю неправильно, поэтому я могу проверить свое обслуживание.

4b9b3361

Ответ 1

В вашем тестовом примере вы ничего не получите в своем конструкторе - вы можете настроить объект, который хотите протестировать, в методе 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

Ответ 2

Если вы не собираетесь тестировать контроллеры (с клиентом, потому что контроллер, вызываемый таким образом, будет использовать новый контейнер), ваш тестовый класс должен просто расширить 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');
  }
  ...
}

Дополнительная информация: http://symfony.com/doc/current/testing/doctrine.html

Заметки:

  1. Чтобы иметь свежее ядро и службы для каждого теста, я рекомендую использовать метод setUp вместо setUpBeforeClass (как в принятом ответе).
  2. Ядро всегда доступно через static::$kernel (после загрузки).
  3. Также работает в Symfony 3 и 4.

Ответ 3

Если вы не хотите делать тесты в приложении, но в автономном комплекте, я бы предложил вам взглянуть на очень подробный ответ этого question.