複習 PHPUnit 順手寫了小程式做實驗。
PHPUnit 為了讓各個不同的 test case 不會因為 super globals 變數而互相影響,設計了 「backupGlobals」這個功能。先來看範例程式:
class MyTest extends TestCase
{
public function testOne()
{
$GLOBALS['test'] = 123;
$this->assertArrayHasKey('test', $GLOBALS);
}
public function testTwo()
{
$this->assertArrayHasKey('test', $GLOBALS);
}
}
範例中 testOne() 修改了 $GLOBALS 變數的內容,如果在不使用「backupGlobals」的情況下,在 testTwo() 中的 $GLOBALS 也會保留 testOne() 修改過的內容,使 testTow() 抓得到「test」這個 key:
$ phpunit MyTest.php
PHPUnit 7.0.2 by Sebastian Bergmann and contributors.
.. 2 / 2 (100%)
Time: 40 ms, Memory: 4.00MB
OK (2 tests, 2 assertions)
也就表示 testOne() 影響到了 testTwo() 的測試結果,這在測試時是不樂見的,各個測試應該有獨立的測試環境,不應該互相影響。
使用「backupGlobals」功能,PHPUnit 會在 test case 執行之前,使用 serialize() 對 super globals 做備份,並在測試結束以後 unserialize() 復原,所以 testOne() 中做的修改就不會影響到 testTwo() 了:
$ phpunit --globals-backup MyTest.php
PHPUnit 7.0.2 by Sebastian Bergmann and contributors.
.F 2 / 2 (100%)
Time: 52 ms, Memory: 4.00MB
There was 1 failure:
1) MyTest::testTwo
Failed asserting that an array has the key 'test'.
/home/johnroyer/tmp/MyTest.php:16
FAILURES!
Tests: 2, Assertions: 2, Failures: 1.
重點來了,因為是使用 serialize() 和 unserialize(),所以只能針對 primitive type 進行備份和還原,如果使用了 object 或是 singleton 時,「backupGlobals」就派不上用場了。這個時候要使用殺手鐧「runTestsInSeparateProcesses」:
/**
* @runTestsInSeparateProcesses
*/
class MyTest extends TestCase
{
....
}
使用這個 annotation 會讓 PHPUnit 為每個 test case 分別 fork 出新的 proccess 進行測試,因此不同 test case 就可以在完全獨立的環境下執行不受影響:
$ phpunit MyTest.php
PHPUnit 7.0.2 by Sebastian Bergmann and contributors.
.F 2 / 2 (100%)
Time: 303 ms, Memory: 4.00MB
There was 1 failure:
1) MyTest::testTwo
Failed asserting that an array has the key 'test'.
/home/johnroyer/tmp/MyTest.php:19
FAILURES!
Tests: 2, Assertions: 2, Failures: 1.
但使用這個殺手鐧也是要付出一點代價:時間。最前二次執行 PHPUnit 時,跑完二個 test case 只花費了 50ms 左右,而開 proccess 來進行測試則花了 300ms。