ZF2-Servicio de simulación solicitado en Module.php
testing zend-framework2 (3)
Con el fin de burlarse del administrador del servicio y las llamadas realizadas con él, puede utilizar la mofa https://github.com/mockery/mockery . Esta biblioteca es independiente del marco, por lo que incluso si utiliza PHPUnit u otra herramienta, debería funcionar.
La mala forma de usarlo, pero debería resolver su problema rápidamente, es sobrecargar la clase usando mockery (''overload: myclass'') donde myclass es la instancia del administrador de servicios.
La mejor manera de usar la biblioteca es usar el patrón de inyección de depedencias para inyectar un simulador del localizador de servicios cuando su aplicación está mejorando para las pruebas.
Una manera fácil de hacerlo es crear una fábrica para su controlador, inyecte el localizador de servicio dentro. Luego, en la prueba, inicia el controlador con el simulacro del localizador de servicios como parámetro.
Estoy tratando de probar un controlador de mi aplicación ZF2. Supongamos que este controlador está en mi módulo A
En el método Module.php
del Module.php
del módulo A
, estoy usando el administrador de servicios para recuperar un servicio de otro módulo, digamos B
, que no estoy cargando.
¿Cómo se puede configurar un simulacro del servicio solicitado en el administrador del servicio? $this->getApplicationServiceLocator()
cuenta que no puedo usar $this->getApplicationServiceLocator()
para hacer esto en mi prueba, ya que esto ya está llamando al método Module.onBootstrap
de mi módulo A
Para publicar un código, esto es lo que estoy haciendo en este momento
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();
mi clase de prueba real
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 simplificado
namespace Application
Class Module
{
public function onBootstrap(MvcEvent $e)
{
$serviceManager = $e->getApplication()->getServiceManager();
$service = $serviceManager->get(''Service/From/Other/Module'');
}
}
No hay suficientes datos aquí para ayudarle directamente. Sería más útil tener la función ValidateCustomerRegistrationTest->getApplicationServiceLocator()
para empezar.
Espero poder ayudarte indirectamente.
Refactorizar podría ser útil
Cuando estoy escribiendo una prueba de unidad, comienzo con algunas reglas personales.
Solo pruebe el código que está probando. Burlarse de TODO lo demás. No es necesario probar algo que ya debería tener sus propias pruebas.
Cómo funciona una función no debería ser importante. Solo la entrada / salida. Esto mantiene su prueba viable incluso cuando el núcleo de una función cambia drásticamente.
/**
* @param MvcEventInterface $event
* @param Service/From/Other/ModuleInterface $service
*
* @return boolean
*/
public function onBootstrap(MvcEventInterface $event, Service/From/Other/ModuleInterface $service)
{
return true;
}
Luego en la clase de prueba:
public function testOnBootstrap(){
$eventMock = $this->getMock(MvcEventInterface::class);
$serviceMock = $this->getMock(ModuleInterface::class);
$module = new Module();
$result = $module->onBootstrap($eventMock, $serviceMock);
$this->assertTrue($result);
}
* Claramente no sé lo que intentas probar
Cuando refactorizar no es una opción
Hay dos tipos de simulacros que pueden ayudar, que se me ocurren desde el principio, simulacro y mockBuilder. Eche un vistazo a la documentación de PHPUnit para Test Doubles .
$serviceMock = $this->getMockBuilder(ServiceManager::class)
->disableOriginalConstructor()
->setMethods([
''__construct'',
''get''
])
->getMock();
$serviceMock
->expects($this->any())
->method(''get'')
->will($this->returnValue(
$this->getMock(ModuleManagerInterface::class)
));
Buena suerte, espero que nos permita saber si podemos ayudarlo más específicamente. También recomendaría ver los Principios Sólidos de la Programación Orientada a Objetos. Uno de los muchos principios de programación que debe hacer que su código sea limpio, fácil de ampliar y fácil de probar.
Una forma de lograr lo que está intentando hacer es forzar una sobrescritura del servicio en el Administrador de servicios antes de enviar la solicitud a su controlador de prueba. Aquí hay un ejemplo de cómo hacerlo (NOTA: dado que lo que está haciendo es durante el proceso de arranque del módulo, es posible que el ejemplo no se traduzca al 100% de su situación).
Al igual que otras personas mencionaron: es posible que desee comprobar si puede refactorizar a un enfoque más limpio, pero esa es otra historia.