Pregunta

Actualmente estoy trabajando con PHPUnit para tratar de desarrollar pruebas junto con lo que estoy escribiendo, sin embargo, actualmente estoy trabajando en escribir el Administrador de sesión y tengo problemas para hacerlo ...

El constructor para la clase de manejo de sesión es

private function __construct()
{
    if (!headers_sent())
    {
        session_start();
        self::$session_id = session_id();
    }
}

Sin embargo, como PHPUnit envía texto antes de comenzar la prueba, cualquier prueba en este Objeto devuelve una prueba fallida, ya que HTTP '' Encabezados '' han sido enviados ...

¿Fue útil?

Solución

Bueno, su administrador de sesión está básicamente roto por diseño. Para poder probar algo, debe ser posible aislarlo de los efectos secundarios. Desafortunadamente, PHP está diseñado de tal manera que fomenta el uso liberal del estado global ( echo , header , exit , session_start etc. etc.).

Lo mejor que puede hacer es aislar los efectos secundarios en un componente, que se pueden intercambiar en tiempo de ejecución. De esa manera, sus pruebas pueden usar objetos simulados, mientras que el código en vivo usa adaptadores, que tienen efectos secundarios reales. Descubrirá que esto no funciona bien con singletons, que supongo que está usando. Por lo tanto, tendrá que usar algún otro mecanismo para distribuir objetos compartidos en su código. Puede comenzar con un registro estático, pero hay soluciones aún mejores si no le importa aprender un poco.

Si no puede hacer eso, siempre tiene la opción de escribir pruebas de integración. P.ej. use el equivalente de PHPUnit de WebTestCase .

Otros consejos

Cree un archivo de arranque para phpunit, que invoca:

session_start();

Luego inicia phpunit de esta manera:

phpunit --bootstrap pathToBootstrap.php --anotherSwitch /your/test/path/

El archivo bootstrap se llama antes que todo lo demás, por lo que el encabezado no se ha enviado y todo debería funcionar bien.

phpUnit imprime la salida a medida que se ejecutan las pruebas, lo que hace que headers_sent () vuelva verdadero incluso en su primera prueba.

Para superar este problema para un conjunto de pruebas completo, simplemente necesita usar ob_start () en su script de configuración.

Por ejemplo, supongamos que tiene un archivo llamado AllTests.php que es lo primero que carga phpUnit. Ese script podría tener el siguiente aspecto:

<?php

ob_start();

require_once 'YourFramework/AllTests.php';

class AllTests {
    public static function suite() {
        $suite = new PHPUnit_Framework_TestSuite('YourFramework');
        $suite->addTest(YourFramework_AllTests::suite());
        return $suite;
    }
}

Tuve el mismo problema y lo resolví llamando a phpunit con la bandera --stderr así:

phpunit --stderr /path/to/your/test

¡Espero que ayude a alguien!

Creo que el "correcto" la solución es crear una clase muy simple (tan simple que no necesite ser probada) que sea un contenedor para las funciones relacionadas con la sesión de PHP, y usarla en lugar de llamar a session_start () , etc. directamente .

En el paso de prueba simulacro de objeto en lugar de una clase de sesión con estado real e inestable.

private function __construct(SessionWrapper $wrapper)
{
   if (!$wrapper->headers_sent())
   {
      $wrapper->session_start();
      $this->session_id = $wrapper->session_id();
   }
}

Me pregunto por qué nadie ha incluido la opción XDebug:

/**
 * @runInSeparateProcess
 * @requires extension xdebug
 */
public function testGivenHeaderIsIncludedIntoResponse()
{
    $customHeaderName = 'foo';
    $customHeaderValue = 'bar';

    // Here execute the code which is supposed to set headers
    // ...

    $expectedHeader = $customHeaderName . ': ' . $customHeaderValue;
    $headers = xdebug_get_headers();

    $this->assertContains($expectedHeader, $headers);
}

¿No puedes usar el buffer de salida antes de comenzar la prueba? Si almacena en búfer todo lo que se emite, no debería tener problemas para configurar ningún encabezado ya que todavía no se habría enviado ninguna salida al cliente en ese momento.

Incluso si el OB se usa en algún lugar dentro de sus clases, es apilable y el OB no debería afectar lo que sucede dentro.

Hasta donde yo sé, Zend Framework utiliza el mismo búfer de salida para sus pruebas de paquete Zend_Session. Puede echar un vistazo a sus casos de prueba para comenzar.

La creación del archivo bootstrap, señaló 4 publicaciones, parece la forma más clara de solucionar esto.

A menudo, con PHP, tenemos que mantener e intentar agregar algún tipo de disciplina de ingeniería a los proyectos heredados que se ensamblan abismalmente. No tenemos el tiempo (o la autoridad) para deshacernos de todo el montón de basura y comenzar de nuevo, por lo que la primera respuesta de troelskn no siempre es posible como un camino a seguir. (Si pudiéramos volver al diseño inicial, entonces podríamos deshacernos de PHP por completo y usar algo más moderno, como ruby ??o python, en lugar de ayudar a perpetuar este COBOL del mundo del desarrollo web).

Si está intentando escribir pruebas unitarias para módulos que usan session_start o setcookie en todos ellos, entonces comenzar la sesión en un archivo boostrap soluciona estos problemas.

Como estoy probando mi bootstrap en este momento (sí, sé que la mayoría de ustedes no hace eso), me encuentro con el mismo problema (tanto header () como session_start ()). La solución que encontré es bastante simple, en el bootstrap de unittest defina una constante y simplemente verifíquela antes de enviar el encabezado o comenzar la sesión:

// phpunit_bootstrap.php
define('UNITTEST_RUNNING', true);

// bootstrap.php (application bootstrap)
defined('UNITTEST_RUNNING') || define('UNITTEST_RUNNING', false);
.....
if(UNITTEST_RUNNING===false){
    session_start();
}

Estoy de acuerdo en que esto no es perfecto por diseño, pero estoy probando una aplicación existente, no es necesario reescribir piezas grandes. También estoy usando la misma lógica para probar métodos privados usando los métodos mágicos __call () y __set ().

public function __set($name, $value){
    if(UNITTEST_RUNNING===true){
       $name='_' . $name;
       $this->$name=$value;
    }
    throw new Exception('__set() can only be used when unittesting!');
 }

Parece que necesita inyectar la sesión para poder probar su código. La mejor opción que he usado es Aura.Auth para el proceso de autenticación y uso de NullSession y NullSegment para las pruebas.

Prueba de aura con sesiones nulas

El marco de Aura está bellamente escrito y puede usar Aura.Auth por sí solo sin ninguna otra dependencia del marco de Aura.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top