PHPUnit и тестирование заголовков

Активист

Активист
Команда форума
Подскажите, кто как тестирует HTTP заголовки через PHPUnit ?

1. Интересует тестирование кодов ответов (200, 301, 302, 404, 500)
2. Посланы ли заголовки
3. Тестирование Content Mime Type (в т.ч. с сharset).
4. Наличие Location
 

AnrDaemon

Продвинутый новичок
Не смешивай заголовки клиента и заголовки сервера.
 

Adelf

Administrator
Команда форума
А ты хочешь запускать как-то контроллеры и смотреть что они нагенерили или все-таки делать полноценный HTTP запрос и проверять заголовки, которые отдаст?
Просто в первом случае - все зависит от архитектуры твоей. Во втором.. там все просто. разве не?
 

Активист

Активист
Команда форума
Adelf, написать тест, который проверит - действительно ли будет отдан в браузер ответ 404 или нет.
Естественно, протестировать подобный код легко (сравнив аттрибут response_code )

PHP:
class Base_Layout_Html {
protected $resonse_code;

public function setResoponseCode( $code ) {
$this->response_code = $code;
return $this;
}

public function function getResponseCode() {
return $this->response_code;
}

public function output()
{
if ($this->response_code == 404) {
header("HTTP/1.0 404 Not Found");
}
}
}
Но, отдаст ли вызов этого кода 404 или например, сгенерирует ошибку (header already sent) или скажем, этот заголовок перекроет другой заголовок в другом участке кода. Вот и надо получить заголовки в буфере.

Поэтому, я тестируя контроллер хочу удостовериться в правильности заголовков.
 

Adelf

Administrator
Команда форума
Тут дело даже не в PHPUnit. Это тесты другого уровня. и тестить надо уже на тестовом веб-сервере. и проверять реальными запросами.
 

Активист

Активист
Команда форума
Спс, xdebug и забыл

Например, тут test404Response фейлится
PHP:
<?php
class HttpTest  extends PHPUnit_Framework_TestCase
{
    /**
    *  @runInSeparateProcess
    */
    public function test302Response()
    {
       header( "Location: /" );
       $this->assertEquals( 302, http_response_code() );
       $this->assertContains("Location: /" , xdebug_get_headers());
    }
  
    /**
    * @runInSeparateProcess
    */
  
    public function test404Response()
    {
        header ("HTTP/1.0 404 Not found" );
        header( "Location: /" );
      
        $this->assertEquals( 404, http_response_code() );
    }
}
Код:
keeper@home:/var/www/v4.localhost/httpdocs$ ./Tests/phpunit.phar --bootstrap App/Bootstrap/Bootstrap.php Tests/Base/http.php
PHPUnit 4.4.1 by Sebastian Bergmann.

.F

Time: 149 ms, Memory: 4.75Mb

There was 1 failure:

1) HttpTest::test404Response
Failed asserting that 302 matches expected 404.

/var/www/v4.localhost/httpdocs/Tests/Base/http.php:23

FAILURES!
Tests: 2, Assertions: 3, Failures: 1.
keeper@home:/var/www/v4.localhost/httpdocs$
 

Активист

Активист
Команда форума

hell0w0rd

Продвинутый новичок
Так не надо тестировать php. Это не юнит-тесты, это функциональные тесты. Надо запускать сервер и слать на него запросы.
 

AmdY

Пью пиво
Команда форума
header( "Location: /" ); - WTF?
ты либо тестируешь контроллер реально ходя на урл каким нибудь guzzle или аналогом. либо делаешь контроллеры не срущими в аутпут
$response->setHeader('Location', '/');
$response->setBody('........');

$response->hasHeader('Location');
 

fixxxer

К.О.
Партнер клуба
Активист, если уж есть желание говнокодить без объекта Response, можно так:

-header ("HTTP/1.0 404 Not found" );
+http_response_code(404);
 

Активист

Активист
Команда форума
Активист, если уж есть желание говнокодить без объекта Response, можно так:

-header ("HTTP/1.0 404 Not found" );
+http_response_code(404);
Ну вообще-то этот пример я отправил что бы можно было с чего скопипастить.

Дергая заголовки можно проверить, установилась ли кука или установлен ли редирект. Т.е. проверить, как отработает код. Как без получения заголовков буфера протестировать установку кук? Или например при 404 ошибке выдавать 200 код при json ответе. Покрывать эти участки кода нужно, и проверять результат.

header( "Location: /" ); - WTF?
ты либо тестируешь контроллер реально ходя на урл каким нибудь guzzle или аналогом. либо делаешь контроллеры не срущими в аутпут
$response->setHeader('Location', '/');
$response->setBody('........');
$response->hasHeader('Location');
Я хожу на URL через диспетчер
PHP:
<?php
/**
* @author keeper
*/

if ( !defined("APP_INDEX_ROUTE") ) {
  
    define("APP_INDEX_ROUTE", "Test/Route/Index");
}

class Base_Controllers_DispatchTest extends PHPUnit_Framework_TestCase
{
    /**
    * @expectedException Base_Route_Exception
    */
    public function testUnknownRouteDispatch()
    {
        new Base_Route("Path/To/UnknownRoute");
    }
  
    /**
    * @expectedException Base_Exception_404
    */
    public function testUnknownRouteDispatch404()
    {
        new Base_Route("Path/To/UnknownRoute");
    }
  
    /**
    * @expectedException Base_Exception
    */
    public function testUnknownRouteDispatchBaseException()
    {
        new Base_Route("Path/To/UnknownRoute");
    }
  
    /**
    * @covers App_Test_Controllers_Route::ProtectedMethod
    * @expectedException Base_Controllers_Dispatch_Exception
    */
    public function testDispatchCallProtectedMethod()
    {
        $dispatch = new Base_Controllers_Dispatch( new Base_Route("Test/Route/ProtectedMethod") );
        $this->assertEquals("Test", $dispatch->getRoute()->getModule());
        $this->assertEquals("App_Test_Controllers_Route", $dispatch->getRoute()->getController());
        $this->assertEquals("ProtectedMethod", $dispatch->getRoute()->getMethod());
        $dispatch->call();
    }
  
    /**
    * @covers App_Test_Controllers_Route::ProtectedMethod
    * @expectedException Base_Exception_404
    */
    public function testDispatchCallProtectedMethod404()
    {
        (new Base_Controllers_Dispatch( new Base_Route("Test/Route/ProtectedMethod") ))->call();
    }
  
    /**
    * @covers App_Test_Controllers_Route::ProtectedMethod
    * @expectedException Base_Exception
    */
    public function testDispatchCallProtectedMethodBaseException()
    {
        (new Base_Controllers_Dispatch( new Base_Route("Test/Route/ProtectedMethod") ))->call();
    }

    public function testCreateExistsDispatchEntity()
    {
        $dispatch = new Base_Controllers_Dispatch( new Base_Route("Test/Route/Index") );
        return $dispatch;
    }
  
    /**
    * @depends testCreateExistsDispatchEntity
    * @covers Base_Controller
    */
    public function testDispatchAttributes(Base_Controllers_Dispatch $dispatch)
    {
        $this->assertInstanceOf("Base_Route", $dispatch->getRoute());
        $this->assertInstanceOf("App_Test_Controllers_Route", $dispatch->getControllerEntity() );
        $this->assertInstanceOf("Base_Controller", $dispatch->getControllerEntity() );
        $this->assertInstanceOf("Base_Controllers_Dispatch", $dispatch->getControllerEntity()->getParentDispatcher() );
    }
  
    /**
    * @depends testCreateExistsDispatchEntity
    */
    public function testDispatchCallMethodMethod(Base_Controllers_Dispatch $dispatch)
    {
        $call_result = $dispatch->call();
        $this->assertInstanceOf("Base_Controller", $call_result);
        return $call_result;
    }
  
    /**
    * @depends testDispatchCallMethodMethod
    */
    public function testPreAndPostDispatch(Base_Controller $controller)
    {
        $this->assertTrue($controller->pre_dispatched);
        $this->assertTrue($controller->post_dispatched);
    }
  
    public function testCallRewrited()
    {
       $route = new Base_Route( "/UnitTest/Rewrite/Engine/Testing/44" );

       $this->assertEquals("Test/Route/Rewrited", $route->getPath());
       $this->assertTrue($route->isRewrited());
       $this->assertEquals(2, sizeof($route->getArgs()));
       $this->assertTrue($route->getArgs()[0]);
       $this->assertEquals(44, $route->getArgs()[1]);
      
      
       $dispatch = new Base_Controllers_Dispatch( $route );
       $dispatch->call();
    }
  
    /**
    * @runInSeparateProcess
    * @preserveGlobalState disabled
    */
    public function test404HtmlDispatch()
    {

        require_once 'App/Bootstrap.php'; // Bootstrap в Eclipse PHPUnit не подключается при @preserveGlobalState
      
        $dispatch = new Base_Controllers_Dispatch( new Base_Route("Test/Route/Response404") );
       $controller = $dispatch->call();
      
       $controller->getLayout()
       ->setTemplatePath("Tests/App/Layouts/for-layout-test.tpl.php")
       ->output();
      
       $this->expectOutputString("<html><head><title>Ошибка 404</title></head><body>Ошибка. Страница не найдена</body></html>");
       $this->assertEquals(404, http_response_code());
       $this->assertContains("Content-Type: application/html; charset=utf8", xdebug_get_headers());
      
    }
  
    /**
    * @runInSeparateProcess
    * @preserveGlobalState disabled
    */
    public function test404XRequestedWithDispatch()
    {
        require_once 'App/Bootstrap.php'; // Bootstrap в Eclipse PHPUnit не подключается при @preserveGlobalState
      
        $_SERVER['X-REQUESTED-WITH'] = "XMLHttpRequest";
      
       $dispatch = new Base_Controllers_Dispatch( new Base_Route("Test/Route/Response404") );

       $controller = $dispatch->call();
  
       $controller->getLayout()
       ->setTemplatePath("Tests/App/Layouts/for-layout-test.tpl.php")
       ->output();
      
       $this->expectOutputString(json_encode(array("response_code" => 404, "title" => "Ошибка 404", "content" => "Ошибка. Страница не найдена")));
       $this->assertEquals(200, http_response_code());
       $this->assertContains("Content-Type: application/json", xdebug_get_headers());
    }
  
  
}
 
Сверху