Slim Framework 端点单元测试

Posted

技术标签:

【中文标题】Slim Framework 端点单元测试【英文标题】:Slim Framework endpoint unit testing 【发布时间】:2013-07-24 08:05:41 【问题描述】:

我正在尝试为我的小型超薄框架应用程序编写一些 phpUnit 测试,但在文档中看不到任何指向执行完整请求和断言响应的方法(包含文本或 200状态,或任何东西,真的)。

有没有人发现/使用过的方法?

【问题讨论】:

过去 12 个月内在他们的帮助论坛上讨论过,但不清楚是否曾经解决:help.slimframework.com/discussions/questions/… 【参考方案1】:

以下是测试 Slim 应用程序的示例:

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

【讨论】:

【参考方案2】:

好的,所以我能够对其进行粗加工并使其正常工作。这是端点测试类的示例。

假设您在开发环境中工作,您可以对自己的本地主机执行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."/users/124";
  $response = $this->loadEndpoint($url);
  $expected = '["name":"John Smith","email":"john@acme.com"]';
  $this->assertEquals($response['body'], $expected);

在单独的测试中,您可以测试 API 调用响应的任何其他属性:

public function testGetUserMimeType() 
  $this->printToConsole(__METHOD__);
  $url = $this->api_url."/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 新手。

【讨论】:

以上是关于Slim Framework 端点单元测试的主要内容,如果未能解决你的问题,请参考以下文章

Django REST framework 单元测试

指定端口时,Spring Boot Actuator 端点的单元测试不起作用

iPhone单元测试链接问题,找不到DevToolsBundleInjection.framework

运行时单元测试 Django Rest Framework 身份验证

如何在 django-rest-framework 中对权限进行单元测试?

Zend Framework 和 Doctrine 2 - 我的单元测试是不是足够?