2013-07-24 97 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用于模拟我们的应用程序处理的请求。