phpunitの`@runInSeparateProcess`,`@preserveGlobalState`利用時の注意点
概要
phpでアプリケーションを書いていて、当然unit testも書いています。
unit testを書いている中でmockが必要なパターンが出てくると思います。
その際にとても有名なmockery
を使っています
んで、mockery
を色々と使ってると@runInSeparateProcess
,@preserveGlobalState
が必要になることが多くあります
@runInSeparateProcess
@preserveGlobalState
正確な情報は上記のリンク先にお任せして、要は別のプロセスにしてグローバル参照させない設定という感じですね。
ぶち当たった課題
別プロセスで稼働するということはtestの中でsetUpBeforeClass
,tearDownAfterClass
を設定していた時に予期せぬタイミングで実行されるという...
具体的に
echo
を仕込んで実際に動かしながら見てみる
テスト対象のクラス
a.php
<?php namespace StaticMethods; class StaticMethods { public static function func() { return "this is static method. \n"; } }
テストコード test.php
<?php namespace Tests; use Mockery as m; use PHPUnit\Framework\TestCase; use StaticMethods\StaticMethods; /** * @group Test */ class Test extends TestCase { public static function setUpBeforeClass() { parent::setUpBeforeClass(); echo 'setUpBeforeClass'."\n"; } public static function tearDownAfterClass() { parent::tearDownAfterClass(); echo 'tearDownAfterClass'."\n"; } /** * @runInSeparateProcess * @preserveGlobalState disabled */ public function test_a() { $mock = m::mock('overload:' . StaticMethods::class); $mock->shouldReceive('func')->andReturn('is this static method ?'); echo(StaticMethods::func()."\n"); } public function test_b() { echo(StaticMethods::func()."\n"); } }
本体予想していたechoの期待値は
- setUpBeforeClass ->
- is this static method ? -> test_aのecho
- this is static method. -> test_bのecho
- tearDownAfterClass ->
実際のechoの期待値は
- setUpBeforeClass -> test_aの設定の別プロセス or もともとの setUpBeforeClass
- setUpBeforeClass -> test_aの設定の別プロセス or もともとの setUpBeforeClass
- is this static method ? -> test_aのecho
- tearDownAfterClass -> test_aの設定の別プロセス or もともとの tearDownAfterClass
- this is static method. -> test_bのecho
- tearDownAfterClass -> test_aの設定の別プロセス or もともとの tearDownAfterClass
この結果何が問題になるか
tearDownAfterClass
とはテストケースの最後に実行されるメソッドです。それが、まだテストが実行中にも関わらず実行されてしまう...😨
この現象でちょっとハマりました
回避方法
何通りかあると思う
- そもそも影響しないように
runInSeparateProcess
の設定があるテストは別に切り出す tearDownAfterClass
を諦めてtearDown
を使う- テストケースが多い場合は遅くなる可能性あるけど致し方なし
- 順番を考慮する
@runInSeparateProcess
の付いているテストを最後に持ってくる。そーすると下記のようになる- setUpBeforeClass -> もともとのプロセスのsetUpBeforeClass
- this is static method. -> test_bのecho
- setUpBeforeClass -> test_aの設定の別プロセスのsetUpBeforeClass
- is this static method ? -> test_aのecho
- tearDownAfterClass -> test_aの設定の別プロセス or もともとの tearDownAfterClass
- tearDownAfterClass -> test_aの設定の別プロセス or もともとの tearDownAfterClass
最後
微妙にハマり、半日は浪費してしまった気がする...😰
プロセスが並列に動いて処理をしているので(プロセス同士は互いに考慮せずに稼働する)、タイミングというか、ケースによっては必ずこの上記のような順序になるとは限らない...😓
副作用は色々あるなぁーと実感しました