此節正式開始進入開發的步驟,如先前所提,我們核心價值將會先建置 發文功能的 CURD。
laravel 已經有把 phpunit 放在 framework 內,首先可以先在 terminal 執行確保指令正常:
$ cd Blogger
$ ./vendor/bin/phpunit
PHPUnit 5.7.4 by Sebastian Bergmann and contributors.
. 1 / 1 (100%)
Time: 237 ms, Memory: 10.00MB
OK (1 test, 2 assertions)
看起來相當不錯,接著建立第一個測試案例,這邊注意,我們是開發一個新功能,我建議你可以放在 futures 這個資料夾內:
$ php artisan make:test futures/PostResourceTest
你會在 tests/futures 找到 PostResourceTest,接著我們馬上來編寫第一個測試案例:
/**
* @test
* @group post
*/
public function see_the_post_index()
{
$this->visit(route('posts.index'))->see('文章列表');
//拜訪路由別名是 posts.index 的端點,並且要看到"文章列表"
}
@test 是告知 phpunit 這是一個測試案例,@group 是把這個案例群組在 post,日後要單獨測試群組時相當方便。
方法名稱你可以像我這樣打有意義的文字,或者你可以testIndex
,這樣 @test 就不需要輸入了。
然後執行測試,你會得到第一個紅燈:
$ ./vendor/bin/phpunit
PHPUnit 5.7.4 by Sebastian Bergmann and contributors.
.E 2 / 2 (100%)
Time: 211 ms, Memory: 10.00MB
There was 1 error:
1) PostResourceTest::see_the_post_index
InvalidArgumentException: Route [posts.index] not defined.
/Users/Yish/Sites/Blogger/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php:314
/Users/Yish/Sites/Blogger/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php:693
/Users/Yish/Sites/Blogger/tests/futures/PostResourceTest.php:15
ERRORS!
Tests: 2, Assertions: 2, Errors: 1.
引用自 wiki & 網路著名圖片
測試驅動開發(英語:Test-driven development,縮寫為TDD)是一種軟體開發過程中的應用方法,由極限編程中倡導,以其倡導先寫測試程序,然後編碼實現其功能得名。測試驅動開發始於20世紀90年代。測試驅動開發的目的是取得快速反饋並使用「illustrate the main line」方法來構建程序。
測試驅動開發是戴兩頂帽子思考的開發方式:先戴上實現功能的帽子,在測試的輔助下,快速實現其功能;再戴上重構的帽子,在測試的保護下,通過去除冗餘的代碼,提高代碼質量。測試驅動著整個開發過程:首先,驅動代碼的設計和功能的實現;其後,驅動代碼的再設計和重構。
你會先編寫一個測試案例並且會失敗,接著編寫代碼足夠讓測試通過即可,測試通過之後重構讓他品質更高,接著重構的過程又會紅燈,再次編寫讓程式通過綠燈。不斷的迭代和重構。
我們從 phpunit 的錯誤當中可以看到:
1) PostResourceTest::see_the_post_index
InvalidArgumentException: Route [posts.index] not defined.
錯誤訊息是說我們沒有定義路由,切換到 routes/web.php 定義路由:
Route::resource('posts', 'PostsController');
接著馬上執行測試,要記住只要你進行了新增或者移除等改動程式的過程,都要執行 phpunit。
我們得到了不一樣的錯誤:
There was 1 error:
1) PostResourceTest::see_the_post_index
ReflectionException: Class App\Http\Controllers\PostsController does not exist
看起來是 laravel 在映射的時候找不到 PostsController,接著我們來建立 PostsController:
$ php artisan make:controller PostsController --resource
你會在 Https/Controllers 找到 PostsController
--resource 這個額外的參數是告訴 laravel 你要建立一個 resource 的控制器,他會把 CURD 的空方法先建立進去,是相當方便的功能。
接著我們執行第二次測試,希望這次可以得到不同結果:
There was 1 error:
1) PostResourceTest::see_the_post_index
InvalidArgumentException: The current node list is empty.
他錯誤是說我呼叫的節點是空白的,接著我們來編寫 index 方法當中的內容:
public function index()
{
return view('posts.index'); //等於 View::make('post.index');
}
跟 laravel 說:嘿,幫我渲染出 posts.index 這個視圖好嗎?
接著執行測試:
1) PostResourceTest::see_the_post_index
A request to [http://localhost/posts] failed. Received status code [500].
....
Caused by
InvalidArgumentException: View [posts.index] not found. in /Users/Yish/Sites/Blogger/vendor/laravel/framework/src/Illuminate/View/FileViewFinder.php:137
得到了 500 錯誤,引發原因是因為找不到視圖 posts.index,那就來建立吧:
在 resources/views/
底下建立 posts 資料夾,並且新建一隻檔案 index.blade.php
接著執行測試:
1) PostResourceTest::see_the_post_index
InvalidArgumentException: The current node list is empty.
又得到了節點列表是空白,接下來我們在測試中,期待拜訪這個頁面時能夠看到"文章列表",所以在 index.blade.php 編寫 html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
</body>
</html>
接著一樣執行測試,會得到這樣子的錯誤:
Failed asserting that the page contains the HTML [文章列表]. Please check the content above.
在文本內找不到 "文章列表",接著我們在 html 內新建文章列表:
<h1>文章列表</h1>
執行測試:
$ ./vendor/bin/phpunit
PHPUnit 5.7.4 by Sebastian Bergmann and contributors.
.. 2 / 2 (100%)
Time: 94 ms, Memory: 10.00MB
OK (2 tests, 4 assertions)
恭喜完成了第一個測試案例,為了驗證我們整個流程是否正確,你可以試著把文章列表修改成別的文字,就會出現錯誤:
$ ./vendor/bin/phpunit
PHPUnit 5.7.4 by Sebastian Bergmann and contributors.
.F 2 / 2 (100%)
Time: 97 ms, Memory: 10.00MB
There was 1 failure:
1) PostResourceTest::see_the_post_index
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>我不是</h1>
</body>
Failed asserting that the page contains the HTML [文章列表]. Please check the content above.
/Users/Yish/Sites/Blogger/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Constraints/PageConstraint.php:90
/Users/Yish/Sites/Blogger/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithPages.php:275
/Users/Yish/Sites/Blogger/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithPages.php:291
/Users/Yish/Sites/Blogger/tests/futures/PostResourceTest.php:15
FAILURES!
Tests: 2, Assertions: 4, Failures: 1.
修改回"文章列表",又會得到綠燈:
$ ./vendor/bin/phpunit
PHPUnit 5.7.4 by Sebastian Bergmann and contributors.
.. 2 / 2 (100%)
Time: 96 ms, Memory: 10.00MB
OK (2 tests, 4 assertions)
在這個章節中我們寫了第一個測試案例,並且使其紅燈,逐步編寫後變成綠燈完成了一個 TDD 的 flow,編寫讓測試通過的程式碼即可,不需要過多的干擾。
這個章節主要是要理解 TDD 紅燈,綠燈,重構的流程,依照這樣子的做法在日後章節我們都會這樣做,假設日後有需求變動時也是先修改測試案例得到紅燈再去調整程式碼。
此章節是理解 TDD 開發的基礎,請同學要自己實作練習過再往下一個章節邁進。