Domanda

Attualmente sto lavorando con PHPUnit per provare a sviluppare test insieme a ciò che sto scrivendo, tuttavia, attualmente sto lavorando alla scrittura di Session Manager e sto riscontrando problemi nel farlo ...

Il costruttore per la classe di gestione della sessione è

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

Tuttavia, poiché PHPUnit invia il testo prima che inizi il test, qualsiasi test su questo oggetto restituisce un test fallito, come HTTP " Headers " sono stati inviati ...

È stato utile?

Soluzione

Bene, il gestore della sessione è sostanzialmente rotto dal design. Per poter provare qualcosa, deve essere possibile isolarlo dagli effetti collaterali. Sfortunatamente, PHP è progettato in modo tale da incoraggiare l'uso liberale dello stato globale ( echo , header , exit , session_start ecc. ecc.).

La cosa migliore che puoi fare è isolare gli effetti collaterali in un componente, che può essere scambiato in fase di esecuzione. In questo modo, i tuoi test possono usare oggetti derisi, mentre il codice live usa adattatori, che hanno effetti collaterali reali. Scoprirai che questo non funziona bene con i singoli, che presumo tu stia usando. Quindi dovrai usare qualche altro meccanismo per ottenere oggetti condivisi distribuiti sul tuo codice. Puoi iniziare con un registro statico, ma ci sono soluzioni ancora migliori se non ti dispiace un po 'di apprendimento.

Se non puoi farlo, hai sempre la possibilità di scrivere test di integrazione. Per esempio. usa l'equivalente di PHPUnit di WebTestCase .

Altri suggerimenti

Crea un file bootstrap per phpunit, che chiama:

session_start();

Quindi avvia phpunit in questo modo:

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

Il file bootstrap viene chiamato prima di tutto, quindi l'intestazione non è stata inviata e tutto dovrebbe funzionare correttamente.

phpUnit stampa l'output durante l'esecuzione dei test, facendo sì che headers_sent () ritorni vero anche nel primo test.

Per superare questo problema per un'intera suite di test devi semplicemente usare ob_start () nel tuo script di installazione.

Ad esempio, supponiamo di avere un file chiamato AllTests.php che è la prima cosa caricata da phpUnit. Lo script potrebbe essere simile al seguente:

<?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;
    }
}

Ho avuto lo stesso problema e l'ho risolto chiamando phpunit con --stderr flag in questo modo:

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

Spero che aiuti qualcuno!

Penso che il "giusto" sia la soluzione è quella di creare una classe molto semplice (così semplice da non dover essere testata) che sia un wrapper per le funzioni relative alla sessione di PHP e utilizzarla invece di chiamare direttamente session_start () , ecc. .

Nell'oggetto test pass finto invece di una vera classe di sessione stateful, non verificabile.

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

Mi chiedo perché nessuno abbia elencato l'opzione 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);
}

Non puoi usare il buffering dell'output prima di iniziare il test? Se esegui il buffer di tutto ciò che viene generato, non dovresti avere problemi a impostare le intestazioni poiché nessun output sarebbe stato inviato al client in quel momento.

Anche se OB viene utilizzato da qualche parte all'interno delle tue classi, è impilabile e OB non dovrebbe influenzare ciò che sta accadendo all'interno.

Per quanto ne so, Zend Framework utilizza lo stesso buffer di output per i test del pacchetto Zend_Session. Puoi dare un'occhiata ai loro casi di test per iniziare.

La creazione del file bootstrap, ha sottolineato 4 post, sembra il modo più pulito per aggirare questo.

Spesso con PHP dobbiamo mantenere e cercare di aggiungere una sorta di disciplina ingegneristica ai progetti legacy messi insieme in modo abissale. Non abbiamo il tempo (o l'autorità) di abbandonare l'intera pila di rifiuti e ricominciare, quindi la prima risposta di troelskn non è sempre possibile come via da seguire. (Se potessimo tornare al progetto iniziale, allora potremmo abbandonare del tutto PHP e usare qualcosa di più moderno, come ruby ??o python, piuttosto che aiutare a perpetuare questo COBOL del mondo dello sviluppo web.)

Se stai provando a scrivere unit test per moduli che usano session_start o setcookie attraverso di loro, che iniziare la sessione in un file boostrap risolve questi problemi.

Mentre sto annidando il mio bootstrap in questo momento (sì, so che molti di voi non lo fanno), sto correndo con lo stesso problema (sia header () che session_start ()). La soluzione che ho trovato è piuttosto semplice, nel tuo bootstrap unittest definisci una costante e controllala semplicemente prima di inviare l'intestazione o iniziare la sessione:

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

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

Sono d'accordo sul fatto che questo non sia perfetto in base alla progettazione, ma non sto testando un'applicazione esistente, non si desidera riscrivere parti di grandi dimensioni. Uso anche la stessa logica per testare metodi privati ??usando i metodi magici __call () e __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!');
 }

Sembra che tu debba iniettare la sessione in modo da poter testare il tuo codice. L'opzione migliore che ho usato è Aura.Auth per il processo di autenticazione e l'utilizzo di NullSession e NullSegment per i test.

Test dell'aura con sessioni null

Il framework Aura è ben scritto e puoi usare Aura.Auth da solo senza altre dipendenze del framework Aura.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top