[ Laravel 5.2 文檔 ] 服務 -- 測試

來源:互聯網
上載者:User

1、簡介

Laravel 植根於測試,實際上,內建使用 PHPUnit對測試提供支援是即開即用的,並且 phpunit.xml檔案已經為應用設定好了。架構還提供了方便的輔助方法允許你對應用進行富有表現力的測試。

tests目錄中提供了一個 ExampleTest.php檔案,安裝完新的 Laravel 應用後,只需簡單在命令列運行 phpunit來運行測試。

1.1 測試環境

運行測試的時候,Laravel 自動化佈建配置環境為 testing。Laravel在測試時自動設定 session 和 cache 驅動為數組驅動,這意味著測試時不會持久化儲存 session 和 cache。

如果需要的話你也可以建立其它測試環境配置。 testing環境變數可以在 phpunit.xml檔案中配置。

1.2 定義&運行測試

要建立一個新的測試案例,可以使用如下Artisan命令:

php artisan make:test UserTest

該命令將會在 tests目錄下產生一個新的 UserTest類。然後你可以使用PHPUnit 定義測試方法。要運行測試,簡單從終端執行 phpunit命令即可:

assertTrue(true);    }}

注意:如果你在測試類別中定義自己的 setUp方法,確保在其中調用 parent::setUp。

2、應用測試

Laravel 為產生 HTTP請求、測試輸出、以及填充表單提供了平滑的API。舉個例子,我們看下 tests目錄下包含的 ExampleTest.php檔案:

visit('/')             ->see('Laravel 5')             ->dontSee('Rails');    }}

visit方法產生了一個GET請求, see方法對我們從應用返迴響應中應該看到的給定文本進行斷言。 dontSee方法對給定文本沒有從應用響應中返回進行斷言。在Laravel中這是最基本的有效應用測試。

2.1 與應用互動

當然,除了對響應文本進行斷言之外還有做更多測試,讓我們看一些點選連結和填充表單的例子:

點選連結

在本測試中,我們將為應用產生請求,在返回的響應中“點擊”連結,然後對訪問URI進行斷言。例如,假定響應中有一個“關於我們”的連結:

About Us

現在,讓我們編寫一個測試點擊連結並斷言使用者訪問頁面是否正確:

public function testBasicExample(){    $this->visit('/')         ->click('About Us')         ->seePageIs('/about-us');}

處理表單

Laravel 還為處理表單提供了多個方法。 type, select, check, attach, 和 press方法允許你與所有表單輸入進行互動。例如,我們假設這個表單存在於應用註冊頁面:

 

我們可以編寫測試完成表單並檢查結果:

public function testNewUserRegistration(){    $this->visit('/register')         ->type('Taylor', 'name')         ->check('terms')         ->press('Register')         ->seePageIs('/dashboard');}

當然,如果你的表單包含其他輸入比如選項按鈕或下拉式清單,也可以輕鬆填寫這些欄位類型。這裡是所有表單操作方法列表:

方法 描述
$this->type($text, $elementName) “Type” 文本到給定欄位
$this->select($value, $elementName) “Select” 單選框或下拉式清單
$this->check($elementName) “Check” 複選框
$this->attach($pathToFile, $elementName) “Attach” 檔案到表單
$this->press($buttonTextOrElementName) “Press” 給定文本或name的按鈕
$this->uncheck($elementName) “Uncheck”複選框

處理附件

如果表單包含 file輸入類型,可以使用 attach方法添加檔案到表單:

public function testPhotoCanBeUploaded(){    $this->visit('/upload')         ->name('File Name', 'name')         ->attach($absolutePathToFile, 'photo')         ->press('Upload')         ->see('Upload Successful!');}

2.2 測試JSON API

Laravel 還提供多個協助函數用於測試 JSON API 及其響應。例如, get, post, put, patch, 和 delete方法用於通過多種 HTTP 要求方式發出請求。你還可以輕鬆傳遞資料和頭到這些方法。作為開始,我們編寫測試來產生 POST 請求到 /user並斷言返回的資料是否是 JSON 格式:

post('/user', ['name' => 'Sally'])             ->seeJson([                 'created' => true,             ]);    }}

seeJson方法將給定數組轉化為 JSON,然後驗證應用返回的整個 JSON 響應中的 JSON 片段。因此,如果在 JSON 響應中有其他屬性,只要給定片段存在的話測試依然會通過。

驗證JSON值匹配

如果你想要驗證給定數組和應用返回的JSON能夠精確匹配,使用 seeJsonEquals方法:

post('/user', ['name' => 'Sally'])             ->seeJsonEquals([                 'created' => true,             ]);    }}

驗證JSON資料結構匹配

還可以驗證JSON響應是否與指定資料結構匹配,我們使用 seeJsonStructure方法來實現這一功能:

get('/user/1')             ->seeJsonStructure([                 'name',                 'pet' => [                     'name', 'age'                 ]             ]);    }}

上面的例子示範了期望擷取一個包含 name和嵌套 pet對象(該對象包含 name和 age屬性)的 JSON 資料。如果 JSON 響應中包含其它額外鍵 seeJsonStructure也不會失敗,例如,如果 pet對象包含 weight屬性測試仍將通過。

你可以使用*來斷言返回JSON結構包含一個列表,該列表中的每個資料項目都包含至少如下樣本中列出的屬性:

get('/users')             ->seeJsonStructure([                 '*' => [                     'id', 'name', 'email'                 ]             ]);    }}

你還可以使用嵌套的*,在這種情境中,我們可以斷言JSON響應中的每個使用者都包含一個給定屬性集合,而且每個使用者的每個 pet都包含給定屬性集合:

$this->get('/users')     ->seeJsonStructure([         '*' => [             'id', 'name', 'email', `pets` => [                 '*' => [                     'name', 'age'                 ]             ]         ]     ]);

2.3 Session/認證

Laravel提供了多個輔助函數用於在測試期間處理Session,首先,可以使用 withSession方法設定 session 值到給定數組。這在測試請求前擷取 session 資料時很有用:

withSession(['foo' => 'bar'])             ->visit('/');    }}

當然,session的通常用於操作使用者狀態,例如認證使用者。輔助函數 actingAs提供了認證給定使用者為目前使用者的簡單方法,例如,我們使用模型工廠產生和認證使用者:

create();        $this->actingAs($user)             ->withSession(['foo' => 'bar'])             ->visit('/')             ->see('Hello, '.$user->name);    }}

還可以通過傳遞 guard名稱作為 actingAs函數的第二個參數的方式來指定使用哪個 guard來認證給定使用者:

$this->actingAs($user, 'backend')

2.4 禁止中介軟體

測試應用時,為某些測試禁止中介軟體很方便。這種機制允許你將路由和控制器與中介軟體孤立開來做測試,Laravel包含了一個簡單的 WithoutMiddlewaretrait,可以使用該 trait 自動在測試類別中禁止所有中介軟體:

    

如果你只想在某些方法中禁止中介軟體,可以在測試方法中調用 withoutMiddleware方法:

withoutMiddleware();        $this->visit('/')             ->see('Laravel 5');    }}

2.5 自訂HTTP請求

如果你想要在應用中產生自訂HTTP請求並擷取完整的 Illuminate\Http\Response對象,可以使用 call方法:

public function testApplication(){    $response = $this->call('GET', '/');    $this->assertEquals(200, $response->status());}

如果你要產生 POST, PUT, 或者 PATCH請求可以在請求中傳入輸入資料數組,在路由或控制器中可以通過Request執行個體訪問請求資料:

$response = $this->call('POST', '/user', ['name' => 'Taylor']);

2.6 PHPUnit斷言方法

Laravel 為 PHPUnit 測試提供了額外的斷言方法:

方法 描述
->assertResponseOk(); 斷言用戶端響應狀態代碼是否為200
->assertResponseStatus($code); 斷言用戶端響應狀態代碼是否是給定$code
->assertViewHas($key, $value = null); 斷言響應視圖是否包含給定的綁定資料片段
->assertViewHasAll(array $bindings); 斷言視圖是否包含給定綁定資料列表
->assertViewMissing($key); 斷言響應視圖缺失綁定資料片段
->assertRedirectedTo($uri, $with = []); 斷言用戶端是否重新導向到給定URI
->assertRedirectedToRoute($name, $parameters = [], $with = []); 斷言用戶端是否重新導向到給定路由
->assertRedirectedToAction($name, $parameters = [], $with = []); 斷言用戶端是否重新導向到給定action
->assertSessionHas($key, $value = null); 斷言session是否包含給定值
->assertSessionHasAll(array $bindings); 斷言session是否保護眼給定值列表
->assertSessionHasErrors($bindings = [], $format = null); 斷言session是否包含錯誤綁定
->assertHasOldInput(); 斷言sessio包含上次輸入資料

3、處理資料庫

Laravel還提供了多種有用的工具讓測試資料庫驅動的應用更加簡單。首先,你可以使用協助函數 seeInDatabase來斷言資料庫中的資料是否和給定資料集合匹配。例如,如果你想要通過 email 值為 sally@example.com的條件去資料表 users查詢是否存在該記錄 ,我們可以這樣做:

public function testDatabase(){    // 調用應用...    $this->seeInDatabase('users', ['email' => 'sally@foo.com']);}

當然, seeInDatabase方法和其它類似輔助方法都是為了方便起見進行的封裝,你也可以使用其它PHPUnit內建的斷言方法來進行測試。

3.1 每次測試後重設資料庫

每次測試後重設資料庫通常很有用,這樣的話上次測試的資料不會影響下一次測試。

使用遷移

一種方式是每次測試後復原資料庫並在下次測試前重新遷移。Laravel提供了一個簡單的 DatabaseMigrationstrait來自動為你處理。在測試類別上簡單使用該trait如下:

visit('/')             ->see('Laravel 5');    }}

使用事務

另一種方式是將每一個測試案例包裹到一個資料庫事務中,Laravel提供了方便的 DatabaseTransactionstrait自動為你處理:

visit('/')             ->see('Laravel 5');    }}

注意:該trait只在事務中封裝預設資料庫串連。

3.2 模型工廠

測試時,通常需要在執行測試前插入新資料到資料庫。在建立測試資料時,Laravel允許你使用“factories”為每個Eloquent模型定義預設的屬性值集合,而不用手動為每一列指定值。作為開始,我們看一下 database/factories/ModelFactory.php檔案,該檔案包含了一個工廠定義:

$factory->define(App\User::class, function (Faker\Generator $faker) {    return [        'name' => $faker->name,        'email' => $faker->email,        'password' => bcrypt(str_random(10)),        'remember_token' => str_random(10),    ];});

在閉包中,作為工廠定義,我們返回該模型上所有屬性預設測試值。該閉包接收PHP庫 Faker執行個體,從而允許你方便地為測試產生多種類型的隨機資料。

當然,你可以添加更多工廠到 ModelFactory.php檔案。

多個工廠類型

有時候你可能想要為同一個Eloquent模型類產生多個工廠,例如,除了正常使用者外可能你想要為“管理員”使用者產生一個工廠,你可以使用 defineAs方法定義這些工廠:

$factory->defineAs(App\User::class, 'admin', function ($faker) {    return [        'name' => $faker->name,        'email' => $faker->email,        'password' => str_random(10),        'remember_token' => str_random(10),        'admin' => true,    ];});

你可以使用 raw方法擷取基本屬性而不用重複基本使用者工廠中的所有屬性,擷取這些屬性後,只需將你要求的額外值增補進去即可:

$factory->defineAs(App\User::class, 'admin', function ($faker) use ($factory) {    $user = $factory->raw(App\User::class);    return array_merge($user, ['admin' => true]);});

在測試中使用工廠

定義好工廠後,可以在測試或資料庫填充檔案中通過全域的 factory方法使用它們來產生模型執行個體,所以,讓我們看一些產生模型的例子,首先,我們使用 make方法,該方法建立模型但不將其儲存到資料庫:

public function testDatabase(){    $user = factory(App\User::class)->make();    // 使用者模型測試...}

如果你想要覆蓋模型的一些預設值,可以傳遞數組值到 make方法。只有指定值被替換,其他資料保持不變:

$user = factory(App\User::class)->make([    'name' => 'Abigail',]);

還可以建立多個模型集合或者建立給定類型的集合:

// 建立3個 App\User 執行個體...$users = factory(App\User::class, 3)->make();// 建立1個 App\User "admin" 執行個體...$user = factory(App\User::class, 'admin')->make();// 建立3個 App\User "admin" 執行個體...$users = factory(App\User::class, 'admin', 3)->make();

持久化工廠模型

create方法不僅能建立模型執行個體,還可以使用Eloquent的 save方法將它們儲存到資料庫:

public function testDatabase(){    $user = factory(App\User::class)->create();    //使用者模型測試...}

你仍然可以通過傳遞數組到 create方法覆蓋模型上的屬性:

$user = factory(App\User::class)->create([    'name' => 'Abigail',]);

添加關聯關係到模型

你甚至可以持久化多個模型到資料庫。在本例中,我們添加一個關聯到建立的模型,使用 create方法建立多個模型的時候,會返回一個Eloquent集合執行個體,從而允許你使用集合提供的所有便利方法,例如 each:

$users = factory(App\User::class, 3)           ->create()           ->each(function($u) {                $u->posts()->save(factory(App\Post::class)->make());            });

4、 類比

4.1 類比事件

如果你在重度使用Laravel的時間系統,可能想要在測試時類比特定事件。例如,如果你在測試使用者註冊,你可能不想所有 UserRegistered的時間處理器都被觸發,因為這可能會發送歡迎郵件,等等。

Laravel提供可一個方便的 expectsEvents方法來驗證期望的事件被觸發,但同時阻止該事件的其它處理器運行:

expectsEvents(App\Events\UserRegistered::class);        // 測試使用者註冊代碼...    }}

可以使用 doesntExpectEvents方法來驗證給定事件沒有被觸發:

expectsEvents(App\Events\PodcastWasPurchased::class);        $this->doesntExpectEvents(App\Events\PaymentWasDeclined::class);        // Test purchasing podcast...    }}

如果你想要阻止所有事件運行,可以使用 withoutEvents方法:

withoutEvents();        // 測試使用者註冊代碼...    }}

4.2 類比隊列任務

有時候,你可能想要在請求時簡單測試控制器分發的指定任務,這允許你孤立的測試路由/控制器——將其從任務邏輯中分離出去,當然,接下來你可以在一個獨立測試類別中測試工作本身。

Laravel提供了一個方便的 expectsJobs方法來驗證期望的任務被分發,但該任務本身不會被測試:

expectsJobs(App\Jobs\PurchasePodcast::class);        // 測試購買播客代碼...    }}

注意:這個方法只檢查通過 DispatchesJobstrait分發方法分發的任務,並不檢查直接通過 Queue::push分發的任務。

4.3 類比門面

測試的時候,你可能經常想要類比Laravel門面的調用,例如,看看下面的控制器動作:

    

我們可以通過使用 shouldReceive方法類比 Cache門面的調用,該方法返回一個 Mockery類比的執行個體,由於門面通過Laravel服務容器解析和管理,它們比通常的靜態類更具有可測試性。例如,我們來類比 Cache門面的調用:

once()                    ->with('key')                    ->andReturn('value');        $this->visit('/users')->see('value');    }}

注意:不要類比 Request門面,取而代之地,在測試時傳遞輸入到HTTP協助函數如 call和 post。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.