iT邦幫忙

2022 iThome 鐵人賽

DAY 8
2
Modern Web

Laravel 9 漫遊,享受魔法般的極速網頁開發體驗系列 第 8

Day 08:新世界的單元測試,另外加上覆蓋率分析!

  • 分享至 

  • xImage
  •  

昨天我們撰寫好了 InspireControllerInspireService

今天,我們就來寫看看針對兩者的自動化測試吧!

規劃測試項目

複習一下 [Day 8] 再聊自動測試!怎麼為我們的新網頁加上單元測試

在整合測試的部分,我們希望整體的功能最後呈現的是:

  • 如果連線到 inspire,HTTP status 是 200

在單元測試的部分,

我們針對 InspireController,應該要測試:

  • 呼叫 inspire 函式時,應該要呼叫對應的 InspireService->inspire(),並回傳其輸出

我們針對 InspireService,應該要測試:

  • 呼叫 inspire 函式時,應該要能回傳一句名言

整合測試

參考前面的 Day 05:魔法般的建立自動化測試,想好函數名稱反而最難?

我們這次測試檔案命名為 tests/Feature/InspireTest.php

./vendor/bin/sail artisan make:test InspireTest
<?php

namespace Tests\Feature;

use Tests\TestCase;

class InspireTest extends TestCase
{
    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function test_the_inspire_route_returns_a_successful_response()
    {
        $response = $this->get('/inspire/');

        $response->assertStatus(200);
    }
}

單元測試

InspireController 的依賴注入

就像之前一樣,我們要為 InspireController 加上建構子(constructor)的依賴注入(dependency injection)

在 Laravel 9 時,參考對應的 composer.json,我們使用的 PHP 版本,一定是 PHP 8 以上。

"require": {  
    "php": "^8.0.2",  

PHP 8 時,支援了 Constructor property promotion 的寫法,寫法比起之前更加簡潔了!

<?php  
  
namespace App\Http\Controllers;  
  
use App\Services\InspireService;  
  
class InspireController extends Controller  
{  
    /**  
     * @param InspireService $inspireService  
     */  
    public function __construct(  
        private InspireService $inspireService  
    ) {}  
  
    /**  
     * @return string  
     */    public function inspire(): string  
    {  
        return $this->inspireService->inspire();  
    }  
}

依賴注入處理好之後,我們就可以開始撰寫單元測試了

./vendor/bin/sail artisan make:test --unit InspireControllerTest
<?php

namespace Tests\Unit;

use App\Http\Controllers\InspireController;
use App\Services\InspireService;
use PHPUnit\Framework\TestCase;
use Mockery;
use Mockery\MockInterface;

class InspireControllerTest extends TestCase
{
    /**
     * A basic unit test example.
     *
     * @return void
     */
    public function test_inspire_controller_should_call_inspire_service()
    {
        $mock = Mockery::mock(InspireService::class, function (MockInterface $mock) {
            $mock->shouldReceive('inspire')->andReturn('名言');
        });
		$inspiringController = new InspireController($mock);
		$this->assertEquals(
            '名言',
            $inspiringController->inspire()
        );
    }
}
./vendor/bin/sail artisan make:test --unit InspireServiceTest
<?php

namespace Tests\Unit;

use App\Services\InspireService;
use PHPUnit\Framework\TestCase;

class InspireServiceTest extends TestCase
{
    /**
     * A basic unit test example.
     *
     * @return void
     */
    public function test_inspire_service_should_return_string()
    {
        $this->assertIsString(
            (new InspireService())->inspire()
        );
    }
}

測試結果如下

./vendor/bin/sail test

   PASS  Tests\Unit\ExampleTest
  ✓ that true is true

   PASS  Tests\Unit\InspireControllerTest
  ✓ inspire controller should call inspire service

   PASS  Tests\Unit\InspireServiceTest
  ✓ inspire service should return string

   PASS  Tests\Feature\ExampleTest
  ✓ the application returns a successful response

   PASS  Tests\Feature\HelloWorldTest
  ✓ the hello world route returns a successful response
  ✓ the hello world route response have hello world

   PASS  Tests\Feature\InspireTest
  ✓ the inspire route returns a successful response

  Tests:  7 passed

聊聊測試覆蓋率

撰寫完測試之後,我們總是會希望更清楚知道,測試是否已經完整涵蓋我們的服務了。

最好還有一個有百分比的報告,讓我們知道涵蓋的程度多少。

這件事情,在 Laravel Sail 上非常簡單!

首先,我們到專案的 .env 檔案裡面,加上

SAIL_XDEBUG_MODE=coverage

接著,運作測試時,我們加上 --coverage

./vendor/bin/sail test --coverage 

除了看到前面的測試結果,我們還會看到覆蓋率的報告

  Console/Kernel  ...................................................................................... 100.0 %
  Exceptions/Handler  .................................................................................. 100.0 %
  Http/Controllers/Controller  ......................................................................... 100.0 %
  Http/Controllers/InspireController  .................................................................. 100.0 %
  Http/Kernel  ......................................................................................... 100.0 %
  Http/Middleware/Authenticate ........................................................................... 0.0 %
  Http/Middleware/EncryptCookies  ...................................................................... 100.0 %
  Http/Middleware/PreventRequestsDuringMaintenance  .................................................... 100.0 %
  Http/Middleware/RedirectIfAuthenticated ................................................................ 0.0 %
  Http/Middleware/TrimStrings  ......................................................................... 100.0 %
  Http/Middleware/TrustHosts ............................................................................. 0.0 %
  Http/Middleware/TrustProxies  ........................................................................ 100.0 %
  Http/Middleware/ValidateSignature  ................................................................... 100.0 %
  Http/Middleware/VerifyCsrfToken  ..................................................................... 100.0 %
  Models/User  ......................................................................................... 100.0 %
  Providers/AppServiceProvider  ........................................................................ 100.0 %
  Providers/AuthServiceProvider  ....................................................................... 100.0 %
  Providers/BroadcastServiceProvider ..................................................................... 0.0 %
  Providers/EventServiceProvider  ...................................................................... 100.0 %
  Providers/RouteServiceProvider 49 ..................................................................... 88.9 %
  Services/InspireService  ............................................................................. 100.0 %
  View/Components/Alert .................................................................................. 0.0 %

  Total Coverage ........................................................................................ 60.0 %

可以看到,針對我們自己所撰寫的內容來說,覆蓋率是很高的

  Http/Controllers/InspireController  .................................................................. 100.0 %
  Services/InspireService  ............................................................................. 100.0 %

今天對自動化測試,以及測試覆蓋率的討論就到這邊!我們明天見!


上一篇
Day 07:開始用到 Controller 了!來看看 Laravel 9 的 Controller 有什麼不同
下一篇
Day 09:新的資料庫遷移作法:Squashing Migrations
系列文
Laravel 9 漫遊,享受魔法般的極速網頁開發體驗30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
json_liang
iT邦研究生 4 級 ‧ 2022-09-08 11:21:28

https://ithelp.ithome.com.tw/upload/images/20220908/20111580a4tTipenhQ.jpg

test_the_inspire_route_returns_a_successful_response

的部分應該是

 $response = $this->get('/inspire');

ReccaChao iT邦研究生 5 級 ‧ 2022-09-12 12:18:35 檢舉

感謝糾錯!

我要留言

立即登入留言