使用 Datasets 測試多組資料
如果你想要在一個流程測試中,測試多筆資料,你會怎麼做呢?
雖然我們可以把測試拆開,為每筆資料都寫一個測試,但因為測試邏輯與流程是一樣的,如果每一筆資料都寫一個測試,會讓程式碼顯得冗長且非常多餘
遇到這樣的情況,可以考慮使用 Datasets
我們可以在匿名函式中放入一個參數 $email,並呼叫 with() 方法代入一個有多筆信箱資料的陣列
it('can store a contact', function ($firstName) {
login()->post('/contacts', [
'first_name' => $firstName, // 代入 Datasets 資料
'last_name' => faker()->lastName,
'email' => faker()->email,
// ...
])
->assertRedirect('/contacts')
->assertSessionHas('success', 'Contact created');
})->with([
'Allen',
'"Lisa"',
]);
此時這個測試就會被執行兩次,而這兩次都會測試不同的信箱資料
執行測試之後也會顯示為兩個測試
PASS Tests\Feature\Contacts\StoreTest
✓ it can store a contact with (Allen)
✓ it can store a contact with ('"Lisa"')
Datasets 也可以帶入多個參數
it('can store a contact', function ($firstName, $email) {
login()->post('/contacts', [
'first_name' => $firstName,
'last_name' => faker()->lastName,
'email' => $email,
// ...
])
->assertRedirect('/contacts')
->assertSessionHas('success', 'Contact created');
})->with([
['John', faker()->email],
['Hellen', '"test"@email.com'],
]);
可以使用參數拆包的方式,如果沒有在 Datasets 設定資料,就使用預設的資料
it('can store a contact', function (array $data) {
login()->post('/contacts', [
...[
'first_name' => faker()->firstName,
'last_name' => faker()->lastName,
'email' => faker()->email,
// ...
],
...$data
])
->assertRedirect('/contacts')
->assertSessionHas('success', 'Contact created');
})->with([
[[]],
[['email' => faker()->email, 'first_name' => 'John']],
[['email' => '"test"@email.com', 'first_name' => 'Hellen']],
]);
可以在 Datasets 中加上 key 值
it('can store a contact', function (array $data) {
login()->post('/contacts', [
...[
'first_name' => faker()->firstName,
'last_name' => faker()->lastName,
'email' => faker()->email,
// ...
],
...$data
])
->assertRedirect('/contacts')
->assertSessionHas('success', 'Contact created');
})->with([
'empty' => [[]],
'data 1' => [['email' => faker()->email, 'first_name' => 'John']],
'data 2' => [['email' => '"test"@email.com', 'first_name' => 'Hellen']],
]);
這樣測試結果就會顯示你所設定的 key 名稱
PASS Tests\Feature\Contacts\StoreTest
✓ it can store a contact with data set "empty"
✓ it can store a contact with data set "data 1"
✓ it can store a contact with data set "data 2"
設定 Shared Datasets
可以使用 Laravel 中 artisan 的指令 pest:dataset 生成一個 Shared Datasets
php artisan pest:dataset Emails
這個指令會生成一個 tests/Datasets/Emails.php,我們可以在其中定義一個 Datasets
dataset('valid emails', function () {
return ['email A', 'email B']
});
之後就可以在測試中使用這個 Shared Datasets
it('can store a contact', function ($email) {
login()->post('/contacts', [
'first_name' => faker()->firstName,
'last_name' => faker()->lastName,
'email' => $email,
// ...
])
->assertRedirect('/contacts')
->assertSessionHas('success', 'Contact created');
})->with('valid emails'); // 使用 Shared Datasets 資料
Combined Datasets
你可以組合多個 Datasets,測試更多種組合資料。
例如我想測試一個上傳圖片後顯示圖片規格的功能,除了測試圖片類型,例如 jpg、png 或是 webp,每個類型也想測試不同的大小尺寸
use Illuminate\Support\Facades\Storage;
it('can show supported image formats and options', function ($path, $options) {
Storage::fake()->put($path, file_get_contents(__DIR__ . "/../../fixtures/{$path}"))
$response = $this->get(route('image', ['path' => $path, ...$options]));
$response->assertOk();
expect($response->streamedContent())->not->toBeEmpty()->toBeString();
})->with([
['example.jpg', ['w' => 10, 'h' => 10, 'fit' => 'crop']],
['example.jpg', ['w' => 40, 'h' => 40, 'fit' => 'crop']],
['example.jpg', ['w' => 50, 'h' => 50, 'fit' => 'crop']],
['example.png', ['w' => 10, 'h' => 10, 'fit' => 'crop']],
['example.png', ['w' => 40, 'h' => 40, 'fit' => 'crop']],
['example.png', ['w' => 50, 'h' => 50, 'fit' => 'crop']],
['example.webp', ['w' => 10, 'h' => 10, 'fit' => 'crop']],
['example.webp', ['w' => 40, 'h' => 40, 'fit' => 'crop']],
['example.webp', ['w' => 50, 'h' => 50, 'fit' => 'crop']],
]);
上面的寫法重複度有些高,為了測試 10、40 與 50 的尺寸,我們每個圖片都要特地寫三種尺寸,這時候就可以考慮使用組合 Datasets
use Illuminate\Support\Facades\Storage;
it('can show supported image formats and options', function ($path, $options) {
Storage::fake()->put($path, file_get_contents(__DIR__ . "/../../fixtures/{$path}"))
$response = $this->get(route('image', ['path' => $path, ...$options]));
$response->assertOk();
expect($response->streamedContent())->not->toBeEmpty()->toBeString();
})->with([
'example.jpg',
'example.png',
'example.webp',
])->with([
['w' => 40, 'h' => 40, 'fit' => 'crop'],
['w' => 50, 'h' => 50, 'fit' => 'crop'],
['w' => 10, 'h' => 10, 'fit' => 'crop'],
]);
顯示的測試結果如下
PASS Tests\Feature\Image\ShowTest
✓ it can show supported image formats and options with ('example.jpg') / (array(40, 40, 'crop'))
✓ it can show supported image formats and options with ('example.jpg') / (array(50, 50, 'crop'))
✓ it can show supported image formats and options with ('example.jpg') / (array(10, 10, 'crop'))
✓ it can show supported image formats and options with ('example.png') / (array(40, 40, 'crop'))
✓ it can show supported image formats and options with ('example.png') / (array(50, 50, 'crop'))
✓ it can show supported image formats and options with ('example.png') / (array(10, 10, 'crop'))
✓ it can show supported image formats and options with ('example.webp') / (array(40, 40, 'crop'))
✓ it can show supported image formats and options with ('example.webp') / (array(50, 50, 'crop'))
✓ it can show supported image formats and options with ('example.webp') / (array(10, 10, 'crop'))