javck
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- tags: laravel --- # 快速開始你的第一次單元測試 ### 簡介 Laravel 內建就支援單元測試。事實上,Laravel 預設就支持用 PHPUnit 來做測試,並為你的應用配置好了 phpunit.xml 檔案。框架還提供了一些便利的幫助函數來讓你更直觀的測試你的應用 預設情況下,應用的 tests 目錄中包含兩個子目錄:Feature 和 Unit 單元測試(Unit Tests)是針對你的程式碼中非常少,而且相對獨立的部分來進行的測試。實際上,大部分單元測試都是針對單個方法進行的。單元測試不會啟動你的應用因此無法取用應用資料庫或框架的服務 功能測試(Feature Tests)則是針對大部分的程式碼進行的測試,包括多個物件之間的交互,甚至是對 JSON 端點的完整 HTTP 請求等等。總的來說,你大部分的測試都應該是功能測試,這些測試能讓你確保你的系統能夠正常運作 Feature 和 Unit 目錄中都提供一個 ExampleTest.php 測試範例文件。安裝一個新的 Laravel 應用之後,在命令行下運行 phpunit 或者是 test 命令,即可運行測試 `php artisan test` ### 環境 在使用 phpunit 進行測試時,Laravel 將根據 phpunit.xml 文件設定的環境變數自動將環境設置為 testing,並將 Session 及緩存以 array 的驅動形式來保存,也就是說在測試時不會持久保存任何 Session 或緩存資料 你可以隨意創建其它必要的測試環境配置。testing 環境變數可以在 phpunit.xml 文件中修改,但是在運行測試之前,請確保使用以下命令來清除配置的緩存! `php artisan config:clear` #### .env.testing 檔案 此外,你還可以在你的專案根目錄下創建一個 .env.testing 檔案,在運行單元測試或使用帶有 --env=testing 選項的 Artisan 命令時, .env 文件中的變數將會被這個文件覆蓋 ### 快速開始 #### 生成一個測試用例: 使用 Artisan 命令 make:test 創建一個新的測試用例: ``` // 在 Feature 目錄下創建一個測試類別... php artisan make:test UserTest // 在 Unit 目錄下創建一個測試類別... php artisan make:test UserTest --unit ``` >技巧: > >可以使用 stub publishing 自定義測試 stub 測試類別一旦生成,你就可以像使用 PHPUnit 一樣定義測試方法。 執行 phpunit 或者 php artisan test 命令即可執行測試: ```php //tests\Unit\ExampleTest.php namespace Tests\Unit; use PHPUnit\Framework\TestCase; class ExampleTest extends TestCase { /** * 一個基礎的測試用例 * * @return void */ public function testBasicTest() { $this->assertTrue(true); } } ``` >注意: > >如果要在你的測試類別中定義自己的 setUp / tearDown 方法,請確保呼叫了父類別中的 parent::setUp() / parent::tearDown() 方法。 #### 執行測試 你可以使用 phpunit 執行檔來執行測試如下: `./vendor/bin/phpunit` 除 phpunit 命令之外, 您還可以使用 Artisan 的 test 命令來運行你的測試。Artisan 測試運行器提供了關於當前正在運行的測試的更多訊息,以便於日常開發與調試,推薦使用: `php artisan test` 此外,任何可以傳遞給 phpunit 命令的參數也可以傳遞給 Artisan 的 test 命令: `php artisan test --testsuite=feature --stop-on-failure` ### 實作展示 #### Step 1.生成 posts 表格 建立 posts 表格的 Migration 檔案 `php artisan make:migration create_posts_table` 編輯 Migration 內容如下: ```php //database\migrations\xxxx_xx_xx_xxxxxx_create_posts_table.php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreatePostsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title', 50); $table->longText('content'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('posts'); } } ``` 執行 migrate 來生成 posts 表格 `php artisan migrate` 生成 Post.php 作為 Eloquent 模型 `php artisan make:model Post` #### Step 2.建立假資料工廠 建立 PostFactory.php 檔案,該檔案用來定義生成的欄位資料 `php artisan make:factory PostFactory` 編輯 PostFactory.php 的內容如下: ```php //database\factories\PostFactory.php namespace Database\Factories; use App\Models\Post; use Illuminate\Database\Eloquent\Factories\Factory; class PostFactory extends Factory { /** * The name of the factory's corresponding model. * * @var string */ protected $model = Post::class; /** * Define the model's default state. * * @return array */ public function definition() { return [ 'title' => $this->faker->word, 'content' => $this->faker->paragraph ]; } } ``` #### Step 3.新增&編輯控制器 新增 PostController.php 用來處理 posts 表格的 CRUD 輸入以下指令來新增空白的 PostController.php `php artisan make:controller PostController` 編輯 PostController.php 內容如下: ```php //app\Http\Controllers\PostController.php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Post; use Symfony\Component\HttpFoundation\Response; class PostController extends Controller { public function index(){ $posts = Post::get(); return $posts; } public function show(Request $request,$id){ $post = Post::findOrFail($id); return $post; } public function store(Request $request){ $data = ['title' => $request->title , 'content' => $request->content]; return response()->noContent(Response::HTTP_CREATED); //回傳201狀態碼 } } ``` #### Step 4.撰寫路由 在 routes/web.php 加入對應路由 ```php //routes\web.php Route::get('/posts','App\Http\Controllers\PostController@index'); Route::post('/posts/store','App\Http\Controllers\PostController@store'); Route::match(['get','post'],'/posts/{id}','App\Http\Controllers\PostController@show'); ``` #### Step 5.新增測試用例 新增一個功能測試用例 `php artisan make:test PostTest` #### Step 6.編輯測試用例 首先載入 Post 模型 以及 RefreshDatabase ,前者用於控制資料庫,後者則用於重置資料庫 ```php //tests\Feature\PostTest.php namespace Tests\Feature; use Tests\TestCase; use App\Models\Post; use Illuminate\Foundation\Testing\RefreshDatabase; class PostTest extends TestCase { use RefreshDatabase; //每次執行時都要重整資料庫 //測試是否正確的建立5筆資料 public function test_posts_count() { Post::factory()->count(5)->create(); //生成五筆假資料 $posts = Post::get(); $this->assertCount(5,$posts); //確認資料筆數 } //測試 /posts 路徑能否正常訪問 public function test_index_get() { Post::factory()->count(5)->create(); //生成五筆假資料 $response = $this->get('/posts'); $response->assertStatus(200); //確認狀態碼 } //測試 /posts 路徑能否看到指定的標題 public function test_index_see() { Post::factory()->count(5)->create(); //生成五筆假資料 $response = $this->get('/posts'); $post = Post::first(); $response->assertSee($post->title); } //測試 /posts/{id} 路徑能否正常用get訪問 public function test_show_get() { Post::factory()->count(5)->create(); //生成五筆假資料 $post = Post::first(); $response = $this->get("/posts/{$post->id}"); $response->assertStatus(200); } //測試 /posts/{id} 路徑能否正常用post訪問 public function test_show_post() { Post::factory()->count(5)->create(); //生成五筆假資料 $post = Post::first(); $response = $this->post("/posts/{$post->id}"); $response->assertStatus(200); } //測試 /posts/store 路徑能否正常用來新增資料 public function test_store_post() { $post = Post::factory()->make(); $response = $this->post('/posts/store',['title'=>$post['title'],'content'=>$post['content'] ]); $response->assertStatus(201); } } ``` #### Step 7.執行測試 執行所有測試用例的命令 `php artisan test` 如果測試成功會顯示綠色的打勾,反之失敗則會顯示紅色,並且說明錯誤的程式碼 ![](https://i.imgur.com/TrU8Add.png) ### 進階技巧 #### 並行測試 預設情況下,Laravel 和 PHPUnit 會在單一線程依序地執行每個測試。假如你覺得測試所需要花費的時間過久就可以考慮以多線程並行的方式來大幅縮減測試所需的時間。要進行並行測試,只需要在 test 命令後面加上 --parallel 選項即可 `php artisan test --parallel` 啟動並行時,預設 Laravel 將會盡可能的使用機器上所有的 CPU,但是你還是可以去限制所要給它使用的數量,透過 --processes 選項 `php artisan test --parallel --processes=4`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully