Process
簡介
Laravel provides an expressive, minimal API around the Symfony Process component, allowing you to conveniently invoke external processes from your Laravel application. Laravel's process features are focused on the most common use cases and a wonderful developer experience.
呼叫 Process
若要呼叫 Process,可以使用 Process
Facade 提供的 run
與 start
方法。run
方法會呼叫 Process,並等待該 Process 執行完畢。而 start
方法會以非同步方式執行 Process。我們將在此文件中詳細討論這兩種方法。首先,我們先來看看如何執行一個基本的同步 Process 並取得其執行結果:
1use Illuminate\Support\Facades\Process;23$result = Process::run('ls -la');45return $result->output();
1use Illuminate\Support\Facades\Process;23$result = Process::run('ls -la');45return $result->output();
當然,run
方法回傳的 Illuminate\Contracts\Process\ProcessResult
實體還包含了多種可用於檢查 Process 執行結果的實用方法:
1$result = Process::run('ls -la');23$result->successful();4$result->failed();5$result->exitCode();6$result->output();7$result->errorOutput();
1$result = Process::run('ls -la');23$result->successful();4$result->failed();5$result->exitCode();6$result->output();7$result->errorOutput();
擲回 Exception
若在取得 Process 執行結果後,希望能讓終止代碼 (Exit Code) 大於 0 的狀況 (表示執行失敗) 擲回 Illuminate\Process\Exceptions\ProcessFailedException
,可以使用 throw
與 throwIf
方法。若 Process 並未執行失敗,則會回傳 Process 執行結果的實體:
1$result = Process::run('ls -la')->throw();23$result = Process::run('ls -la')->throwIf($condition);
1$result = Process::run('ls -la')->throw();23$result = Process::run('ls -la')->throwIf($condition);
Process 選項
當然,你可能會需要在呼叫 Process 前自訂該 Process 的行為。在 Laravel 中,可以調整許多 Process 的功能,例如工作目錄 (Working Directory)、逾時與環境變數等。
工作目錄路徑
可以使用 path
方法來指定 Process 的工作目錄。若未呼叫此方法,則該 Process 會繼承目前執行 PHP Script 的工作目錄:
1$result = Process::path(__DIR__)->run('ls -la');
1$result = Process::path(__DIR__)->run('ls -la');
輸入
可以通過 input
方法來以「標準輸入 (Standard Input)」提供輸入給 Process:
1$result = Process::input('Hello World')->run('cat');
1$result = Process::input('Hello World')->run('cat');
逾時
預設情況下,Process 會在執行超過 60 秒後擲回 Illuminate\Process\Exceptions\ProcessTimedOutException
實體。不過,可以使用 timeout
方法來自定此行為:
1$result = Process::timeout(120)->run('bash import.sh');
1$result = Process::timeout(120)->run('bash import.sh');
或者,若要完全禁用 Process 的逾時,可以呼叫 forever
方法:
1$result = Process::forever()->run('bash import.sh');
1$result = Process::forever()->run('bash import.sh');
idleTimeout
方法可用來指定 Process 在不回傳任何輸出下可執行的最大秒數:
1$result = Process::timeout(60)->idleTimeout(30)->run('bash import.sh');
1$result = Process::timeout(60)->idleTimeout(30)->run('bash import.sh');
環境變數
可以使用 env
方法來提供環境變數給 Process。被呼叫的 Process 也會繼承在系統中所定義的所有環境變數:
1$result = Process::forever()2 ->env(['IMPORT_PATH' => __DIR__])3 ->run('bash import.sh');
1$result = Process::forever()2 ->env(['IMPORT_PATH' => __DIR__])3 ->run('bash import.sh');
若想從呼叫的 Process 中移除繼承的環境變數,可以提供一個值為 false
的環境變數:
1$result = Process::forever()2 ->env(['LOAD_PATH' => false])3 ->run('bash import.sh');
1$result = Process::forever()2 ->env(['LOAD_PATH' => false])3 ->run('bash import.sh');
TTY 模式
tty
方法可用來在 Process 上啟用 TTY 模式。TTY 模式會將 Process 的 Input 與 Output 連結到你的程式的 Input 與 Output,讓你的 Process 能打開如 Vim 或 Nano 之類的 Process:
1Process::forever()->tty()->run('vim');
1Process::forever()->tty()->run('vim');
Process 的輸出
剛才提到過,可以使用 output
(stdout) 與 errorOutput
(stderr) 方法來在 Process 結果上取得 Process 的輸出:
1use Illuminate\Support\Facades\Process;23$result = Process::run('ls -la');45echo $result->output();6echo $result->errorOutput();
1use Illuminate\Support\Facades\Process;23$result = Process::run('ls -la');45echo $result->output();6echo $result->errorOutput();
不過,也可以在呼叫 run
方法時傳入一個 Closure 作為第二個引數來即時取得輸出。該 Closure 會收到兩個引數:輸出的「類型 (Type)」(stdout
或 stderr
) 與輸出字串本身:
1$result = Process::run('ls -la', function (string $type, string $output) {2 echo $output;3});
1$result = Process::run('ls -la', function (string $type, string $output) {2 echo $output;3});
Laravel 也提供了 seeInOutput
與 seeInErrorOutput
方法。通過這兩個方法,就可以方便地判斷給定的字串是否包含在該 Process 的輸出中:
1if (Process::run('ls -la')->seeInOutput('laravel')) {2 // ...3}
1if (Process::run('ls -la')->seeInOutput('laravel')) {2 // ...3}
關閉 Process 的輸出
若 Process 會寫入大量不必要的輸出,可以完全關閉取得輸出來減少記憶體使用。若要關閉取得輸出,請在建構 Process 時呼叫 quietly
方法:
1use Illuminate\Support\Facades\Process;23$result = Process::quietly()->run('bash import.sh');
1use Illuminate\Support\Facades\Process;23$result = Process::quietly()->run('bash import.sh');
管道
有時候,我們可能會想使用某個 Process 的輸出來作為另一個 Process 的輸入。這個動作我們一般會說是把 Process 的輸出「Pipe」到另一個 Process。Process
Facade 提供的 pipe
方法能讓我們輕鬆進行此動作。pipe
方法會同步執行被 Pipe 的Process,並回傳管道中最後一個 Process 的結果:
1use Illuminate\Process\Pipe;2use Illuminate\Support\Facades\Process;34$result = Process::pipe(function (Pipe $pipe) {5 $pipe->command('cat example.txt');6 $pipe->command('grep -i "laravel"');7});89if ($result->successful()) {10 // ...11}
1use Illuminate\Process\Pipe;2use Illuminate\Support\Facades\Process;34$result = Process::pipe(function (Pipe $pipe) {5 $pipe->command('cat example.txt');6 $pipe->command('grep -i "laravel"');7});89if ($result->successful()) {10 // ...11}
若不需要為組成管道的個別 Process 進行自訂,則只需要傳入一組指令字串的陣列給 pipe
方法即可:
1$result = Process::pipe([2 'cat example.txt',3 'grep -i "laravel"',4]);
1$result = Process::pipe([2 'cat example.txt',3 'grep -i "laravel"',4]);
可以在呼叫 pipe
方法時傳入一個 Closure 作為第二個引數來即時取得輸出。該 Closure 會收到兩個引數:輸出的「類型 (Type)」(stdout
或 stderr
) 與輸出字串本身:
1$result = Process::pipe(function (Pipe $pipe) {2 $pipe->command('cat example.txt');3 $pipe->command('grep -i "laravel"');4}, function (string $type, string $output) {5 echo $output;6});
1$result = Process::pipe(function (Pipe $pipe) {2 $pipe->command('cat example.txt');3 $pipe->command('grep -i "laravel"');4}, function (string $type, string $output) {5 echo $output;6});
Laravel 可讓你使用 as
方法來為管道中的各個 Process 指派一個字串索引鍵。該索引鍵也會傳入提供給 pipe
方法的輸出 Closure,讓你能判斷輸出屬於哪個 Process:
1$result = Process::pipe(function (Pipe $pipe) {2 $pipe->as('first')->command('cat example.txt');3 $pipe->as('second')->command('grep -i "laravel"');4})->start(function (string $type, string $output, string $key) {5 // ...6});
1$result = Process::pipe(function (Pipe $pipe) {2 $pipe->as('first')->command('cat example.txt');3 $pipe->as('second')->command('grep -i "laravel"');4})->start(function (string $type, string $output, string $key) {5 // ...6});
非同步的 Process
run
方法會同步呼叫 Process,而 start
方法可用來非同步地呼叫 Process。這樣一來,你的程式就可以繼續執行其他任務,並讓 Process 在背景執行。Process 被呼叫後,可以使用 running
方法來判斷該 Process 是否還在執行:
1$process = Process::timeout(120)->start('bash import.sh');23while ($process->running()) {4 // ...5}67$result = $process->wait();
1$process = Process::timeout(120)->start('bash import.sh');23while ($process->running()) {4 // ...5}67$result = $process->wait();
讀者可能已經注意到,可以通過呼叫 wait
方法來等待 Process 完成執行,然後再取得 Process 的結果實體:
1$process = Process::timeout(120)->start('bash import.sh');23// ...45$result = $process->wait();
1$process = Process::timeout(120)->start('bash import.sh');23// ...45$result = $process->wait();
Process IDs and Signals
id
方法可用來取得正在執行的 Process 由作業系統指派的 Process ID:
1$process = Process::start('bash import.sh');23return $process->id();
1$process = Process::start('bash import.sh');23return $process->id();
可以使用 signal
方法來向正在執行的 Process 傳送「訊號 (Signal)」。請參考《PHP 說明文件》以瞭解預先定義的 Signal 常數列表:
1$process->signal(SIGUSR2);
1$process->signal(SIGUSR2);
非同步 Process 的輸出
當非同步 Process 正在執行時,可以使用 output
與 errorOutput
方法來取得該 Process 目前的完整輸出。而 latestOutput
與 latestErrorOutput
可用來存取自從上一次取得輸出後該 Process 所產生的最新輸出:
1$process = Process::timeout(120)->start('bash import.sh');23while ($process->running()) {4 echo $process->latestOutput();5 echo $process->latestErrorOutput();67 sleep(1);8}
1$process = Process::timeout(120)->start('bash import.sh');23while ($process->running()) {4 echo $process->latestOutput();5 echo $process->latestErrorOutput();67 sleep(1);8}
與 run
方法類似,start
方法也可以在呼叫時傳入一個 Closure 作為第二個引數來即時取得輸出。該 Closure 會收到兩個引數:輸出的「類型 (Type)」(stdout
或 stderr
) 與輸出字串本身:
1$process = Process::start('bash import.sh', function (string $type, string $output) {2 echo $output;3});45$result = $process->wait();
1$process = Process::start('bash import.sh', function (string $type, string $output) {2 echo $output;3});45$result = $process->wait();
Instead of waiting until the process has finished, you may use the waitUntil
method to stop waiting based on the output of the process. Laravel will stop waiting for the process to finish when the closure given to the waitUntil
method returns true
:
1$process = Process::start('bash import.sh');23$process->waitUntil(function (string $type, string $output) {4 return $output === 'Ready...';5});
1$process = Process::start('bash import.sh');23$process->waitUntil(function (string $type, string $output) {4 return $output === 'Ready...';5});
併行的 Process
Laravel 也讓管理平行的、非同步的 Process 集區 (Pool) 變的非常容易,讓你能輕鬆的同步執行多個任務。若要執行非同步 Process 集區,請執行 pool
方法。請傳入一個 Closure 給 pool
方法,該 Closure 會收到 Illumiante\Process\Pool
的實體。
在該 Closure 中,可以定義屬於該集區的 Process。使用 start
方法開始 Process 集區後,可以使用 running
方法來存取一組包含正在執行的 Process 的 Collection:
1use Illuminate\Process\Pool;2use Illuminate\Support\Facades\Process;34$pool = Process::pool(function (Pool $pool) {5 $pool->path(__DIR__)->command('bash import-1.sh');6 $pool->path(__DIR__)->command('bash import-2.sh');7 $pool->path(__DIR__)->command('bash import-3.sh');8})->start(function (string $type, string $output, int $key) {9 // ...10});1112while ($pool->running()->isNotEmpty()) {13 // ...14}1516$results = $pool->wait();
1use Illuminate\Process\Pool;2use Illuminate\Support\Facades\Process;34$pool = Process::pool(function (Pool $pool) {5 $pool->path(__DIR__)->command('bash import-1.sh');6 $pool->path(__DIR__)->command('bash import-2.sh');7 $pool->path(__DIR__)->command('bash import-3.sh');8})->start(function (string $type, string $output, int $key) {9 // ...10});1112while ($pool->running()->isNotEmpty()) {13 // ...14}1516$results = $pool->wait();
就像這樣,可以使用 wait
方法來等待集區 Process 完成執行並解析這些 Process 的執行結果。wait
方法會回傳一個可使用陣列存取的物件 (Array Accessible Object),讓你能使用其索引鍵來存取集區中各個 Process 的 Process 執行結果實體:
1$results = $pool->wait();23echo $results[0]->output();
1$results = $pool->wait();23echo $results[0]->output();
或者,也可以使用方便的 concurrently
方法來開始一組非同步 Process 集區,並馬上開始等待其執行結果。當與 PHP 的陣列解構功能搭配使用時,使用此方法就可取得富含表達性的語法:
1[$first, $second, $third] = Process::concurrently(function (Pool $pool) {2 $pool->path(__DIR__)->command('ls -la');3 $pool->path(app_path())->command('ls -la');4 $pool->path(storage_path())->command('ls -la');5});67echo $first->output();
1[$first, $second, $third] = Process::concurrently(function (Pool $pool) {2 $pool->path(__DIR__)->command('ls -la');3 $pool->path(app_path())->command('ls -la');4 $pool->path(storage_path())->command('ls -la');5});67echo $first->output();
命名的 Pool Process
使用數字索引鍵來存取 Process 集區並不是很有表達性。因此,Laravel 可讓你使用 as
方法來為集區中的各個 Process 指派一個字串索引鍵。該索引鍵也會傳入提供給 start
方法的 Closure,讓你能判斷輸出屬於哪個 Process:
1$pool = Process::pool(function (Pool $pool) {2 $pool->as('first')->command('bash import-1.sh');3 $pool->as('second')->command('bash import-2.sh');4 $pool->as('third')->command('bash import-3.sh');5})->start(function (string $type, string $output, string $key) {6 // ...7});89$results = $pool->wait();1011return $results['first']->output();
1$pool = Process::pool(function (Pool $pool) {2 $pool->as('first')->command('bash import-1.sh');3 $pool->as('second')->command('bash import-2.sh');4 $pool->as('third')->command('bash import-3.sh');5})->start(function (string $type, string $output, string $key) {6 // ...7});89$results = $pool->wait();1011return $results['first']->output();
Pool Process IDs and Signals
由於 Process 集區的 running
方法提供了一組包含集區中所有已呼叫 Process 的 Collection,因此你可以輕鬆地存取集區中相應的 Process ID:
1$processIds = $pool->running()->each->id();
1$processIds = $pool->running()->each->id();
而且,也可以在 Process 集區上使用 signal
方法來方便地傳送 Signal 給集區中的每一個 Process:
1$pool->signal(SIGUSR2);
1$pool->signal(SIGUSR2);
測試
許多 Laravel 的服務都提供了能讓你輕鬆且表達性地撰寫測試的方法,而 Laravel 的 Process 服務也不例外。使用 Process
Facade 的 fake
方法,能讓你指定要 Laravel 在執行 Process 時回傳一組模擬的執行結果。
模擬 Process
若要瞭解 Laravel 中模擬 Process 的功能,我們先來想像有個 Route 會呼叫一個 Process:
1use Illuminate\Support\Facades\Process;2use Illuminate\Support\Facades\Route;34Route::get('/import', function () {5 Process::run('bash import.sh');67 return 'Import complete!';8});
1use Illuminate\Support\Facades\Process;2use Illuminate\Support\Facades\Route;34Route::get('/import', function () {5 Process::run('bash import.sh');67 return 'Import complete!';8});
在測試此 Route 時,我們可以不帶任何引數呼叫 Process
Facade 上的 fake
方法,讓 Laravel 在每一個被呼叫的 Process 上回傳一組模擬的成功 Process 執行結果。此外,我們還可以 Assert 判斷給定的 Process 是否已執行:
1<?php23use Illuminate\Process\PendingProcess;4use Illuminate\Contracts\Process\ProcessResult;5use Illuminate\Support\Facades\Process;67test('process is invoked', function () {8 Process::fake();910 $response = $this->get('/import');1112 // Simple process assertion...13 Process::assertRan('bash import.sh');1415 // Or, inspecting the process configuration...16 Process::assertRan(function (PendingProcess $process, ProcessResult $result) {17 return $process->command === 'bash import.sh' &&18 $process->timeout === 60;19 });20});
1<?php23use Illuminate\Process\PendingProcess;4use Illuminate\Contracts\Process\ProcessResult;5use Illuminate\Support\Facades\Process;67test('process is invoked', function () {8 Process::fake();910 $response = $this->get('/import');1112 // Simple process assertion...13 Process::assertRan('bash import.sh');1415 // Or, inspecting the process configuration...16 Process::assertRan(function (PendingProcess $process, ProcessResult $result) {17 return $process->command === 'bash import.sh' &&18 $process->timeout === 60;19 });20});
1<?php23namespace Tests\Feature;45use Illuminate\Process\PendingProcess;6use Illuminate\Contracts\Process\ProcessResult;7use Illuminate\Support\Facades\Process;8use Tests\TestCase;910class ExampleTest extends TestCase11{12 public function test_process_is_invoked(): void13 {14 Process::fake();1516 $response = $this->get('/import');1718 // Simple process assertion...19 Process::assertRan('bash import.sh');2021 // Or, inspecting the process configuration...22 Process::assertRan(function (PendingProcess $process, ProcessResult $result) {23 return $process->command === 'bash import.sh' &&24 $process->timeout === 60;25 });26 }27}
1<?php23namespace Tests\Feature;45use Illuminate\Process\PendingProcess;6use Illuminate\Contracts\Process\ProcessResult;7use Illuminate\Support\Facades\Process;8use Tests\TestCase;910class ExampleTest extends TestCase11{12 public function test_process_is_invoked(): void13 {14 Process::fake();1516 $response = $this->get('/import');1718 // Simple process assertion...19 Process::assertRan('bash import.sh');2021 // Or, inspecting the process configuration...22 Process::assertRan(function (PendingProcess $process, ProcessResult $result) {23 return $process->command === 'bash import.sh' &&24 $process->timeout === 60;25 });26 }27}
剛才也提到過,在 Process
Facade 上呼叫 fake
方法會讓 Laravel 為每個 Process 回傳沒有輸出的 Process 執行結果。不過,你可以使用 Process
Facade 的 result
方法來輕鬆地指定模擬 Process 的輸出與結束代碼 (Exit Code):
1Process::fake([2 '*' => Process::result(3 output: 'Test output',4 errorOutput: 'Test error output',5 exitCode: 1,6 ),7]);
1Process::fake([2 '*' => Process::result(3 output: 'Test output',4 errorOutput: 'Test error output',5 exitCode: 1,6 ),7]);
模擬特定的 Process
讀者可能已經在前一個例子中注意到,通過 Process
Facade,就可以通過傳入一組陣列給 fake
方法來指定各個 Process 的模擬執行結果。
陣列的索引鍵代表要模擬的指令格式,以及其相應的執行結果。可使用 *
字元來作為萬用字元。沒有被模擬的 Process 指令會被實際執行。可以使用 Process
Facade 的 result
方法來為這些指令建立模擬的執行結果:
1Process::fake([2 'cat *' => Process::result(3 output: 'Test "cat" output',4 ),5 'ls *' => Process::result(6 output: 'Test "ls" output',7 ),8]);
1Process::fake([2 'cat *' => Process::result(3 output: 'Test "cat" output',4 ),5 'ls *' => Process::result(6 output: 'Test "ls" output',7 ),8]);
若不需要自定模擬 Process 的終止代碼或錯誤輸出,那麼使用字串來指定 Process 的模擬結果可能會更方便:
1Process::fake([2 'cat *' => 'Test "cat" output',3 'ls *' => 'Test "ls" output',4]);
1Process::fake([2 'cat *' => 'Test "cat" output',3 'ls *' => 'Test "ls" output',4]);
模擬 Process 序列
若要測試的程式碼會以相同指令來呼叫多個 Process,則可為各個 Process 呼叫指定不同的 Process 模擬執行結果。若要為各個 Process 呼叫設定各自的執行結果,請使用 Process
Facade 的 sequence
方法:
1Process::fake([2 'ls *' => Process::sequence()3 ->push(Process::result('First invocation'))4 ->push(Process::result('Second invocation')),5]);
1Process::fake([2 'ls *' => Process::sequence()3 ->push(Process::result('First invocation'))4 ->push(Process::result('Second invocation')),5]);
模擬非同步 Process 的生命週期
到目前為止,我們主要針對使用 run
方法同步呼叫的 Process 討論要如何進行模擬。不過,若要測試的程式碼中有使用 start
來非同步呼叫 Process,就需要使用更複雜的方法來模擬 Process。
舉例來說,假設有下列 Route 會觸發非同步 Process:
1use Illuminate\Support\Facades\Log;2use Illuminate\Support\Facades\Route;34Route::get('/import', function () {5 $process = Process::start('bash import.sh');67 while ($process->running()) {8 Log::info($process->latestOutput());9 Log::info($process->latestErrorOutput());10 }1112 return 'Done';13});
1use Illuminate\Support\Facades\Log;2use Illuminate\Support\Facades\Route;34Route::get('/import', function () {5 $process = Process::start('bash import.sh');67 while ($process->running()) {8 Log::info($process->latestOutput());9 Log::info($process->latestErrorOutput());10 }1112 return 'Done';13});
若要正確模擬此 Process,我們需要能夠描述 running
方法要回傳幾次 true
。此外,我們可能還需要指定要依序回傳的多行輸出。為此,我們可以使用 Process
Facade 的 describe
方法:
1Process::fake([2 'bash import.sh' => Process::describe()3 ->output('First line of standard output')4 ->errorOutput('First line of error output')5 ->output('Second line of standard output')6 ->exitCode(0)7 ->iterations(3),8]);
1Process::fake([2 'bash import.sh' => Process::describe()3 ->output('First line of standard output')4 ->errorOutput('First line of error output')5 ->output('Second line of standard output')6 ->exitCode(0)7 ->iterations(3),8]);
讓我們來仔細看看上面的範例。使用 output
與 errorOutput
方法,我們可以指定要依序回傳的多行輸出。exitCode
方法可用來指定模擬 Process 最終的終止代碼。最後,iterations
方法可用來指定 running
方法要回傳幾次 true
。
可用的 Assertion
就像剛才提到過的,Laravel 為功能測試 (Feature Test) 提供了多個 Process 的 Assertion。我們會在接下來的部分討論這些 Assertion。
assertRan
判斷給定 Process 是否已被呼叫:
1use Illuminate\Support\Facades\Process;23Process::assertRan('ls -la');
1use Illuminate\Support\Facades\Process;23Process::assertRan('ls -la');
也可傳入一個 Closure 給 assertRun
方法。該 Closure 會收到 Process 的實體與 Process 的執行結果,讓你能檢查 Process 上的設定。若讓該 Closure 回傳 true
,則該 Assertion 就會通過 (Pass):
1Process::assertRan(fn ($process, $result) =>2 $process->command === 'ls -la' &&3 $process->path === __DIR__ &&4 $process->timeout === 605);
1Process::assertRan(fn ($process, $result) =>2 $process->command === 'ls -la' &&3 $process->path === __DIR__ &&4 $process->timeout === 605);
傳給 assertRun
Closure 的 $process
是 Illuminate\Process\PendingProcess
的實體,而 $result
是 Illuminate\Contracts\Process\ProcessResult
的實體。
assertDidntRun
判斷給定 Process 是否未被呼叫:
1use Illuminate\Support\Facades\Process;23Process::assertDidntRun('ls -la');
1use Illuminate\Support\Facades\Process;23Process::assertDidntRun('ls -la');
與 assertRun
方法類似,assertDidntRun
方法也可被傳入一個 Closure。傳給 assertDidntRun
的 Closure 會收到 Process 實體與 Process 的執行結果,讓你能檢查 Process 上的設定。若該 Closure 回傳 true
,則該 Assertion 就會失敗 (Fail):
1Process::assertDidntRun(fn (PendingProcess $process, ProcessResult $result) =>2 $process->command === 'ls -la'3);
1Process::assertDidntRun(fn (PendingProcess $process, ProcessResult $result) =>2 $process->command === 'ls -la'3);
assertRanTimes
判斷給定 Process 是否被呼叫了給定次數:
1use Illuminate\Support\Facades\Process;23Process::assertRanTimes('ls -la', times: 3);
1use Illuminate\Support\Facades\Process;23Process::assertRanTimes('ls -la', times: 3);
也可傳入一個 Closure 給 assertRanTimes
方法。該 Closure 會收到 Process 的實體與 Process 的執行結果,讓你能檢查 Process 上的設定。若讓該 Closure 回傳 true
,且該 Process 被呼叫了給定的次數,則該 Assertion 就會通過 (Pass):
1Process::assertRanTimes(function (PendingProcess $process, ProcessResult $result) {2 return $process->command === 'ls -la';3}, times: 3);
1Process::assertRanTimes(function (PendingProcess $process, ProcessResult $result) {2 return $process->command === 'ls -la';3}, times: 3);
避免漏掉的 Process
若想在個別測試或整個測試套件中,確保所有呼叫的 Process 都被模擬,則可呼叫 preventStrayProcesses
方法。呼叫該方法後,若某個 Process 沒有相對應的模擬結果,該 Process 就不會被執行,而會擲回一個 Exception:
1use Illuminate\Support\Facades\Process;23Process::preventStrayProcesses();45Process::fake([6 'ls *' => 'Test output...',7]);89// Fake response is returned...10Process::run('ls -la');1112// An exception is thrown...13Process::run('bash import.sh');
1use Illuminate\Support\Facades\Process;23Process::preventStrayProcesses();45Process::fake([6 'ls *' => 'Test output...',7]);89// Fake response is returned...10Process::run('ls -la');1112// An exception is thrown...13Process::run('bash import.sh');