昨天我們撰寫好了 InspireController
和 InspireService
。
今天,我們就來寫看看針對兩者的自動化測試吧!
複習一下 [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
加上建構子(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 %
今天對自動化測試,以及測試覆蓋率的討論就到這邊!我們明天見!
test_the_inspire_route_returns_a_successful_response
的部分應該是
$response = $this->get('/inspire');
感謝糾錯!