2013-07-24 153 views
9

我試着寫我的小超薄框架應用中的一些PHPUnit測試,但沒有看到在指向一個方式做一個完整的請求和響應斷言(無論是文檔的任何地方包含文本或200狀態,或者其他任何內容)。修身框架端點單元測試

有沒有辦法做到這一點,任何人都已經找到/使用?

+0

在過去的12個月裏,他們在他們的幫助論壇上曾經討論過,但是它的問題是否已經解決:http://help.slimframework.com/discussions/questions/222-how-to-test-a-silm -app – Kristian

回答

3

好了,我可以粗糙,並使其發揮作用。這是一個端點測試類的例子。

假設你在開發環境中工作,可以執行curl請求你的本地主機,承諾回購之前,因此測試。

首先,創建類:

class ApiEndpointsTest extends PHPUnit_Framework_TestCase 
{ 
    protected $api_url = "http://localhost/api/v1"; 

    //create a function that will allow you to call API endpoints at-will. 
    private function loadEndpoint($url) { 
     $ch = curl_init(); 
     curl_setopt($ch, CURLOPT_URL, $url); 
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
     $output = curl_exec($ch); 
     $info = curl_getinfo($ch); 
     curl_close($ch); 
     return array(
      'body' => $output, 
      'info' => $info 
     ); 
    } 

    //this allows you to write messages in the test output 
    private function printToConsole($statement) { 
     fwrite(STDOUT, $statement."\n"); 
    } 

利用這一點,你可以寫一個測試功能的特定端點響應:

//this will test the actual body of the response against something expected. 
public function testGetUserResponse() { 
    $this->printToConsole(__METHOD__); 
    $url = $this->api_url."https://stackoverflow.com/users/124"; 
    $response = $this->loadEndpoint($url); 
    $expected = '[{"name":"John Smith","email":"[email protected]"}]'; 
    $this->assertEquals($response['body'], $expected); 
} 

在一個單獨的測試,可以測試任何其他財產的API調用回覆:

public function testGetUserMimeType() { 
    $this->printToConsole(__METHOD__); 
    $url = $this->api_url."https://stackoverflow.com/users/124"; 
    $response = $this->loadEndpoint($url); 
    $this->assertEquals($response['info']['content_type'], 'application/json'); 
} 

您的信息屬性選項可以在這裏找到: http://php.net/manual/en/function.curl-getinfo.php

附註:如果有人閱讀這篇文章是PHPUnit的專家,並且知道更好的方法,我有興趣瞭解它 - 我是PHPUnit的新手。

8

這裏是例如,你會如何測試你的應用程序修身:

https://github.com/mac2000/SlimTestable

假設我們有一個簡單的應用:

<?php 
use Slim\Slim; 

require_once 'vendor/autoload.php'; 

$app = new Slim(); 

$app->get('/', function(){ 
    echo 'home'; 
})->name('home'); 

$app->get('/hello/:name', function($name){ 
    echo "hello $name"; 
})->name('hello'); 

$app->map('/login', function() use($app) { 
    if($app->request()->params('login')) { 
     $app->flash('success', 'Successfully logged in'); 
     $app->redirect($app->urlFor('hello', array('name' => $app->request()->params('login')))); 
    } else { 
     $app->flash('error', 'Wrong login'); 
     $app->redirect($app->urlFor('home')); 
    } 
})->via('GET', 'POST'); 

$app->run(); 

我們如何測試它?

創建App類:

<?php // src/App.php 
use Slim\Slim; 

class App extends Slim { 
    function __construct(array $userSettings = array()) 
    { 
     parent::__construct($userSettings); 

     $this->get('/', function(){ 
      echo 'home'; 
     })->name('home'); 

     $this->get('/hello/:name', function($name){ 
      echo "hello $name"; 
     })->name('hello'); 

     $this->map('/login', function() { 
      if($this->request()->params('login')) { 
       $this->flash('success', 'Successfully logged in'); 
       $this->redirect($this->urlFor('hello', array('name' => $this->request()->params('login')))); 
      } else { 
       $this->flash('error', 'Wrong login'); 
       $this->redirect($this->urlFor('home')); 
      } 
     })->via('GET', 'POST'); 
    } 

    /** 
    * @return \Slim\Http\Response 
    */ 
    public function invoke() { 
     $this->middleware[0]->call(); 
     $this->response()->finalize(); 
     return $this->response(); 
    } 
} 

請注意,我們將我們的所有路由到新類的構造函數,也注意到新invoke方法,它一樣做run方法不同的是它返回的響應,而不是呼應了出來。現在

index.php文件可能是這樣的一個:

<?php 
require_once 'vendor/autoload.php'; 

$app = new App(); 
$app->run(); 

,現在是時候做檢查:

<?php // tests/ExampleTest.php 
use Slim\Environment; 

class ExampleTest extends PHPUnit_Framework_TestCase { 
    private $app; 

    public function setUp() 
    { 
     $_SESSION = array(); 
     $this->app = new App(); 
    } 

    public function testHome() { 
     Environment::mock(array(
      'PATH_INFO' => '/' 
     )); 
     $response = $this->app->invoke(); 

     $this->assertContains('home', $response->getBody()); 
    } 

    public function testHello() { 
     Environment::mock(array(
      'PATH_INFO' => '/hello/world' 
     )); 
     $response = $this->app->invoke(); 

     $this->assertTrue($response->isOk()); 
     $this->assertContains('hello world', $response->getBody()); 
    } 

    public function testNotFound() { 
     Environment::mock(array(
      'PATH_INFO' => '/not-exists' 
     )); 
     $response = $this->app->invoke(); 

     $this->assertTrue($response->isNotFound()); 
    } 

    public function testLogin() { 
     Environment::mock(array(
      'PATH_INFO' => '/login' 
     )); 
     $response = $this->app->invoke(); 

     $this->assertTrue($response->isRedirect()); 
     $this->assertEquals('Wrong login', $_SESSION['slim.flash']['error']); 
     $this->assertEquals('/', $response->headers()->get('Location')); 
    } 

    public function testPostLogin() { 
     Environment::mock(array(
      'REQUEST_METHOD' => 'POST', 
      'PATH_INFO' => '/login', 
      'slim.input' => 'login=world' 
     )); 
     $response = $this->app->invoke(); 

     $this->assertTrue($response->isRedirect()); 
     $this->assertEquals('Successfully logged in', $_SESSION['slim.flash']['success']); 
     $this->assertEquals('/hello/world', $response->headers()->get('Location')); 
    } 

    public function testGetLogin() { 
     Environment::mock(array(
      'PATH_INFO' => '/login', 
      'QUERY_STRING' => 'login=world' 
     )); 
     $response = $this->app->invoke(); 

     $this->assertTrue($response->isRedirect()); 
     $this->assertEquals('Successfully logged in', $_SESSION['slim.flash']['success']); 
     $this->assertEquals('/hello/world', $response->headers()->get('Location')); 
    } 
} 

你應該注意幾件事情:

在建立試驗我們正在創建$_SESSION數組用於測試目的並實例化我們的App類對象。

在測試而不是run我們打電話invoke哪些做相同,但返回響應對象。

Environment::mock用於模擬我們的應用程序處理的請求。