今天要來分析內建測試是如何實作的,先來看官方測試範例程式碼。
public function testBasicTest() { $response = $this->get('/');
$response->assertStatus(200); }
|
它對應會跑的 Route 如下:
Route::get('/', function () { return view('welcome'); });
|
Routing 的分析可以再回頭看 Day 12。
這幾會來看 Laravel 是如何從 get()
去取得 response,並得知 statue code 或其他結果。
共用的 Laravel TestCase
Laravel Framework 有一個抽象的 TestCase 類別,首先要了解測試一開始初始化了哪些東西,這可以從 setUp()
得知:
protected function setUp() { if (! $this->app) { $this->refreshApplication(); }
$this->setUpTraits();
foreach ($this->afterApplicationCreatedCallbacks as $callback) { call_user_func($callback); }
Facade::clearResolvedInstances();
Model::setEventDispatcher($this->app['events']);
$this->setUpHasRun = true; }
|
Application 是 Laravel 的核心,所以一開始得先初始化。
protected function refreshApplication() { $this->app = $this->createApplication(); }
public function createApplication() { $app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
return $app; }
|
分析 bootstrap 流程曾提過,bootstrap/app.php
的任務是提供一個可以用在任何場景的 Application,包括測試。而 bootstrap()
方法是為了載入必要的設定檔等,這樣測試程式碼才能正常使用 Config 等元件。
接著,如果 TestCase 有標記特定的 trait,如 DatabaseTransactions,就會有特定的行為,這個 magic 是由 setUpTraits()
所實作的。後面則是清除設定,讓測試可以從乾淨的狀態從頭執行。
get()
與其他 HTTP 相關的方法是寫在 MakesHttpRequests 裡:
public function get($uri, array $headers = []) { $server = $this->transformHeadersToServerVars($headers);
return $this->call('GET', $uri, [], [], [], $server); }
|
其他相關的 HTTP method 與 get()
一樣,最終都會呼叫 call()
:
public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null) { $kernel = $this->app->make(HttpKernel::class);
$files = array_merge($files, $this->extractFilesFromDataArray($parameters));
$symfonyRequest = SymfonyRequest::create( $this->prepareUrlForRequest($uri), $method, $parameters, $cookies, $files, array_replace($this->serverVariables, $server), $content );
$response = $kernel->handle( $request = Request::createFromBase($symfonyRequest) );
if ($this->followRedirects) { $response = $this->followRedirects($response); }
$kernel->terminate($request, $response);
return $this->createTestResponse($response); }
|
仔細觀察可以發現,它跟 index.php 有很多相同的呼叫方法,而 index.php 有多呼叫 Response send 方法。
最後的 response 測試輔助物件則提供了 assertStatus()
等方法,來驗證最後的 response。