Pergunta

Eu estou trabalhando atualmente com PHPUnit para tentar desenvolver testes juntamente com o que estou escrevendo, no entanto, Atualmente estou trabalhando em escrever o Gerenciador de sessão, e estou tendo problemas fazendo isso ...

O construtor para a classe manipulação da sessão é

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

No entanto, como PHPUnit envia texto antes de iniciar o teste, qualquer teste neste objeto retorna um teste falhou, como o HTTP "cabeçalhos" foram enviados ...

Foi útil?

Solução

Bem, seu gerenciador de sessões é basicamente quebrado por design. Para ser capaz de testar alguma coisa, deve ser possível isolá-lo a partir de efeitos colaterais. Infelizmente, PHP é projetado de tal forma que um, que incentiva o uso liberal de estado global (echo, header, exit, session_start etc etc.).

A melhor coisa que você pode fazer, é isolar os efeitos colaterais em um componente, que podem ser trocadas em tempo de execução. Dessa forma, seus testes podem usar objetos escarnecido, enquanto o código ao vivo usa adaptadores, que têm efeitos colaterais reais. Você vai descobrir que este não joga bem com singletons, que eu presumo que você está usando. Então você vai ter que usar algum outro mecanismo para obter objetos compartilhados distribuídos ao seu código. Você pode começar com um registro estático, mas há soluções ainda melhores se você não se importa um pouco de aprendizagem.

Se você não pode fazer isso, você sempre tem a opção de escrever integração-testes. Por exemplo. usar do PHPUnit equivalente a WebTestCase .

Outras dicas

Crie um arquivo de inicialização para phpunit, que chama:

session_start();

Em seguida, iniciar phpunit assim:

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

O arquivo de inicialização é chamado antes de tudo, de modo que o cabeçalho não foi enviado e tudo deve funcionar bem.

phpunit imprime saída como os testes executados causando assim headers_sent () para retornar true mesmo em seu primeiro teste.

Para superar este problema para uma suíte de testes inteira você simplesmente precisa usar ob_start () no seu script de instalação.

Por exemplo, digamos que você tem um arquivo chamado AllTests.php que é a primeira coisa carregado pelo PHPUnit. Esse script pode ser semelhante a seguinte:

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

Eu tive o mesmo problema e eu resolvi-lo chamando phpunit com a bandeira --stderr como esta:

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

Espero que ajude alguém!

Eu acho que a solução "certa" é criar uma classe muito simples (tão simples que não precisa ser testado), que é um wrapper para funções de sessão relacionada com a do PHP, e usá-lo em vez de chamar session_start(), etc. diretamente .

No teste passar objeto de simulação em vez de uma verdadeira aula de estado, não testável sessão.

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

Eu estou querendo opção XDebug por que ninguém tenha listado:

/**
 * @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);
}

Você não pode usar o buffer de saída antes de iniciar o teste? Se você tampão tudo o que está de saída, você não deve ter problemas para configurar quaisquer cabeçalhos como nenhuma saída teria sido ainda enviado para o cliente nesse ponto.

Mesmo OB está em algum lugar usado dentro de suas classes, é empilhável e OB não deve afetar o que está acontecendo lá dentro.

Tanto quanto eu sei Zend Framework usa o mesmo buffer de saída para os seus testes de pacotes Zend_Session. Você pode dar uma olhada em seus casos de teste para você começar.

A criação do arquivo de inicialização, apontou 4 posts parece voltar a forma mais limpa de contornar isso.

Muitas vezes com PHP estamos tendo de manter, e tentar adicionar algum tipo de disciplina de engenharia de projetos legados que são muitíssimo juntos. Não temos o tempo (ou a autoridade) para abandonar toda a pilha de lixo e começar de novo, então a primeira anwer por troelskn nem sempre é possível como um caminho a seguir. (Se pudéssemos voltar para o projeto inicial, então poderíamos abandonar PHP completamente e uso algo mais moderno, como Ruby ou Python, em vez de ajudar a perpetuar este COBOL do mundo do desenvolvimento web.)

Se você está tentando testes de unidade de gravação para módulos que o uso session_start ou setcookie todo-los, do que iniciar a sessão em um arquivo boostrap obtém seus redondos estas questões.

Como eu estou UnitTesting minha inicialização agora (sim, eu sei que a maioria de vocês não fazem isso), eu estou correndo para o mesmo problema (ambos header () e session_start ()). A solução que encontrei é bastante simples, em sua unittest inicialização definir uma constante e simplesmente verificá-lo antes de enviar o cabeçalho ou iniciar a sessão:

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

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

Eu concordo que este não é perfeito por design, mas estou UnitTesting uma aplicação existente, reescrever grandes partes não é desejada. Eu também usando a mesma lógica para testar métodos privados usando a métodos mágicos __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!');
 }

Parece que você precisa para injetar a sessão de modo que você pode testar seu código. A melhor opção que tenho usado é Aura.Auth para o processo de autenticação e usando NullSession e NullSegment para testar.

Aura testes com sessões nulas

O quadro Aura é muito bem escrito e você pode usar Aura.Auth por conta própria, sem quaisquer outras dependências quadro Aura.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top