Laravel Testing - fantasy0107/notes GitHub Wiki
目錄tests中分成Feature和Unit
Unit:small portion of your code(single method)
Feature:large portion of your code
phpunit.xml定義環境變數
- 測試最小單位的邏輯,通常是 Class 的 method
- 不依賴外部「不可控」的環境
- 測試裡不具備邏輯:如 if else, switch case …
- 測試案例之間彼此獨立
- 一次只測試一件事情
- Fast:快速。可以很快看到結果。
- Independent:獨立。測試案例之間不互相影響。
- Repeatable:可重複。可重複執行而不影響預期結果。
- Self-Validating:不需要人工介入驗證。
- Timely:及時。程式完成即可立刻驗證。
- Arrange : 初始化目標物件、相依物件、方法參數、預期結果,或是預期與相依物件的互動方式。
- Assume:預期結果、或預期的互動
- Act : 呼叫目標物件的方法。
- Assert : 驗證是否符合預期。
貼上 web phpinfo() 的資訊
- 所有的單元測試必須要正確
- code 符合它的設計準則
- code 沒有重複
- code 只有最少數量的 class 和 method
- 檢驗你重複出現的錯誤
- 找出 code 中最小的錯誤
- 寫出自動測試是會錯誤但是只要 code 修正就會成功通過
- 修正錯誤
- --debug 詳細列出跑了什麼測試
- --coverage-html
產出 code coverage 報表用 html 的形式 - --filter 要跑怎麼樣的測試 method name
Fixtures (基礎設施)
public function setUp()
{
parent::setUp();
//初始化測試時做的事情在每個方法執行之前
}
public function tearDown()
{
parent::tearDown();
//消滅測試時做的事情在每個方法執行之後
}
- @expectedException ExceptionName - 預計丟出Exception
如果是框架自行提供的Exception \Illuminate\Database\Eloquent\ModelNotFoundException
檔案名稱和要測的檔案名稱一樣+Test
只是在method名稱的部份則是test + methodName + 其它
//artisan
php artisan make:test UserTest --unit
//平常
./vendor/bin/phpunit ....
//有架docker 要跑進 docker 下
docker exec -it php7.1 bash
./vendor/bin/phpunit ....
https://phpunit.de/manual/6.4/en/textui.html#textui.clioptions
Tests/Unit目錄底下就測試service/repository/helper
目錄架構就按照app底下的
//example
/**
* App底下
*/
app\service\UserService
/**
* Tests底下
*/
Tests\Unit\Service\UserService
public function setUp()
{
parent::setUp();
$this->initDatabase();
$this->userRepository = new UserRepository();
}
public function tearDown()
{
$this->resetDatabase();
$this->userRepository = null;
parent::tearDown();
}
使用factory
mock出__construct需要的的class後丟進去
class 是namespace+classname
$userService = new UserService($A, $B, $C, $D);
vendor\bin\phpunit Tests\Unit\Services\UserServiceTest.php
//範例
public function testAdd()
{
$userRepository = $this->createMock('App\TasklistPlatform\Repositories\UserRepository');
$taskRepository = $this->createMock('App\TasklistPlatform\Repositories\TaskRepository');
$userService = new UserService($userRepository, $taskRepository);
$this->assertEquals(2, $userService->add(1,2));
}
PHPUnit
Laravel Seeding
Laravel Factory
--debug // 除錯用
--filter=functionName //測試特定的 test case
factory()->make(); // 產生假資料而且不會新增到資料庫 資料格式會是你 factory 檔案設定的樣子
factory()->create(); // 產生假資料而且會新增到資料庫
use Faker\Generator as Faker;
/**
* 顯示使用者資訊和相關回傳結構 - 成功
*/
public function testShowUserOKWithStatusAndAttributes()
{
$response = $this->withHeaders($this->authorization)
->json('GET', 'api/v1/me');
$response->assertStatus(200)
->assertJsonStructure([
'result',
'data' => [
'thumbnail',
'levelName',
'percentOfThisLevel',
'yCoin',
'diamonds'
]
]);
}
$rule = factory(Rule::class)->create();
$response = $this->withHeaders([
'Authorization' => $this->authorization,
])
->get('/api/rules/'.$rule->id);
$response->assertStatus(200)
->assertJsonStructure([
'id',
'user_id',
'title',
'created_at',
'updated_at',
'deleted_at'
]);
$user = User::first();
$response = $this->withHeaders([
'Authorization' => $this->authorization,
])
->post('/api/users/'.$user->id.'/rules', [
'title' => 'PHPUnit'
]);
$response->assertStatus(201)
->assertJsonStructure([
'id',
'user_id',
'title',
'created_at',
'updated_at'
]);
$rule = Rule::first();
$response = $this->withHeaders([
'Authorization' => $this->authorization,
])
->json('PUT', '/api/users/'.$rule->user_id.'/rules/'.$rule->id, [
'title' => 'PHPUnit putA'
]);
$response->assertStatus(200);
$rule = factory(Rule::class)->create();
$response = $this->withHeaders([
'Authorization' => $this->authorization,
])
->json('DELETE', '/api/users/'.$rule->user_id.'/rules/'.$rule->id);
$response->assertStatus(204);
- Every dependency should be mocked and tests should never touch the database!
- Start testing the entire request / response cycle for a given feature without mocks
public function test_action_events_are_not_created_if_the_action_fails()
{
$user = factory(User::class)->create();
$response = $this->postJson('/api/users/action?action=FailingAction', [
'resources' => [$user->id],
]);
$response->assertStatus(500);
$this->assertCount(0, ActionEvent::all());
}