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

ZF2 - Прошивка, запрошенная в Module.php

Я пытаюсь проверить контроллер моего приложения ZF2. Предположим, что этот контроллер находится в моем модуле A.

В методе onBootstrap Module.php модуля A я использую диспетчер служб для извлечения службы другого модуля, скажем B, который я не загружаю.

Как установить макет запрашиваемой услуги в диспетчере сервисов? Имейте в виду, что я не могу использовать $this->getApplicationServiceLocator() для этого в своем тесте, так как это уже вызывает метод Module.onBootstrap моего модуля A.

Чтобы опубликовать некоторый код, это то, что я делаю в данный момент

bootstrap.php

namespace Application;

use Zend\Mvc\Service\ServiceManagerConfig;
use Zend\ServiceManager\ServiceManager;
use RuntimeException;

class Bootstrap
{
    protected static $serviceManager;

    public static function init()
    {
        $modulePath = static::findParentPath('module');
        $vendorPath = static::findParentPath('vendor');

        if (is_readable($vendorPath . '/autoload.php')) {
            $loader = include $vendorPath . '/autoload.php';
        } else {
            throw new RuntimeException('Cannot locate autoload.php');
        }

        $config = [
            'modules' => [
                'Application',
            ],
            'module_listener_options' => [
                'module_paths' => [
                    $modulePath,
                    $vendorPath
                ]
            ]
        ];

        $serviceManager = new ServiceManager(new ServiceManagerConfig());
        $serviceManager->setService('ApplicationConfig', $config);
        $serviceManager->get('ModuleManager')->loadModules();
        static::$serviceManager = $serviceManager;
    }

    protected static function findParentPath($path)
    {
        $dir = __DIR__;
        $previousDir = '.';
        while (!is_dir($dir . '/' . $path)) {
            $dir = dirname($dir);
            if ($previousDir === $dir) {
                return false;
            }
            $previousDir = $dir;
        }
        return $dir . '/' . $path;
    }

    public static function getServiceManager()
    {
        return static::$serviceManager;
    }
}

Bootstrap::init();

мой фактический класс тестирования

namespace Application\Functional;

use Application\Bootstrap;

use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;

class ValidateCustomerRegistrationTest extends AbstractHttpControllerTestCase
{
    public function setUp()
    {
        $serviceManager = Bootstrap::getServiceManager();
        $applicationConfig = $serviceManager->get('ApplicationConfig');

        $this->setApplicationConfig($applicationConfig);
        parent::setUp();
    }

    public function testRegisterValidUserWithOnlyEquomobiliData()
    {
        $this->getApplicationServiceLocator();
    }
}

Module.php упрощен

namespace Application

Class Module
{
    public function onBootstrap(MvcEvent $e)
    {
        $serviceManager = $e->getApplication()->getServiceManager();
        $service = $serviceManager->get('Service\From\Other\Module');
    }
}
4b9b3361

Ответ 1

Здесь недостаточно данных, чтобы помочь вам напрямую. Было бы более полезно иметь функцию ValidateCustomerRegistrationTest->getApplicationServiceLocator() для стартеров.

Надеюсь, я косвенно помогу вам.

Рефакторинг может быть полезным

Когда я пишу unit test, я начинаю с нескольких личных правил.

Проверяйте только тестируемый код. Откажитесь от ВСЕХ. Нет необходимости тестировать что-то, что уже должно иметь собственные тесты.

Как работает функция, не должно быть важно. Только вход/выход. Это гарантирует, что ваш тест будет жизнеспособным даже тогда, когда корень функции резко изменится.

/**
 * @param MvcEventInterface $event
 * @param Service\From\Other\ModuleInterface $service
 *
 * @return boolean
 */
public function onBootstrap(MvcEventInterface $event, Service\From\Other\ModuleInterface $service)
{
  return true;
}

Тогда в тестовом классе:

public function testOnBootstrap(){
   $eventMock = $this->getMock(MvcEventInterface::class);
   $serviceMock = $this->getMock(ModuleInterface::class);
   $module = new Module();

   $result = $module->onBootstrap($eventMock, $serviceMock);
   $this->assertTrue($result);
}

* Я точно не знаю, что вы пытаетесь проверить

Если рефакторинг не является опцией

Есть два типа макетов, которые могут помочь, которые возникают у меня сразу с места в карьер, насмехаются и mockBuilder. Взгляните на документацию PHPUnit для двухэтажного тестирования.

$serviceMock = $this->getMockBuilder(ServiceManager::class)
    ->disableOriginalConstructor()
    ->setMethods([
        '__construct',
        'get'
    ])
    ->getMock();

$serviceMock
    ->expects($this->any())
    ->method('get')
    ->will($this->returnValue(
        $this->getMock(ModuleManagerInterface::class)
    ));

Удачи, надеюсь, вы можете сообщить нам, если мы сможем помочь вам более конкретно. Я бы также рекомендовал изучить SOLID Принципы объектно-ориентированного программирования. Один из многих принципов программирования, который должен сделать ваш код чистым, легким для расширения и простым в тестировании.

Ответ 2

Один из способов добиться того, что вы пытаетесь сделать, - это принудительно перезаписать службу в Service Manager, прежде чем отправлять запрос на ваш тестовый контроллер. Вот пример о том, как это сделать (ПРИМЕЧАНИЕ: поскольку то, что вы делаете во время процесса начальной загрузки модуля, пример может не переводить 100 % к вашей ситуации).

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

Ответ 3

Чтобы высмеять менеджера сервисов и сделанные с ним вызовы, вы можете использовать mockery https://github.com/mockery/mockery. Эта библиотека является агностикой рамки, поэтому, даже если вы используете PHPUnit или другой инструмент, он должен работать.

Плохой способ использовать его, но он должен быстро решить вашу проблему - перегрузить класс, используя mockingery ('overload: myclass'), где myclass является экземпляром диспетчера служб.

Лучший способ использовать библиотеку - использовать шаблон внедрения depedency, чтобы ввести макет локатора сервисов, когда ваше приложение повышает эффективность тестов.

Легкий способ сделать это - создать factory для вашего контроллера, ввести локатор службы внутри. Затем в вашем тесте вы запускаете контроллер с макетом локатора службы в качестве параметра.