Я пытаюсь написать некоторые тесты PHPUnit для моего небольшого приложения с матовой платформой, но не вижу нигде в документах, которые указывают на способ сделать полный запрос и утверждать ответ (либо содержащий текст, либо статус 200, либо ничего действительно).
Есть ли способ сделать это, чтобы кто-нибудь нашел / использовал?
Вот пример того, как вы можете протестировать свое 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
используется для подделки запросов, обрабатываемых с помощью нашего приложения.
Хорошо, так что я смог его грубо и заставить работать. Ниже приведен пример тестового класса конечной точки.
Предполагая, что вы работаете в среде разработки, вы можете выполнять 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.