片方ずつの話ならググればすぐ出てくるんですけど両方一気にやってるのを見かけなかったので、まぁ組み合わせればいいだけなんですけど備忘録がてら書いておきます。
利用バージョンは以下。
setUP()で対応する場合
// MyTrait.php
trait MyTrait
{
private function privateMethod($arg)
{
return true;
}
}
// traitTest.php use \PHPUnit\Framework\TestCase; use MyTrait; final class MyTreatTest extends TestCase { public function setUp() { $this->mock = $this->getMockForTrait(MyTrait::class); $this->class = new \ReflectionClass($this->mock); } public function testPrivateMethod() { $method = $this->class->getMethod("privateMethod"); $method->setAccessible(true); $argument = "hogefuga"; // optional $this->assertTrue($method->invoke($this->mock, $argument)); } }
setUpBeforeClass()で対応する場合
trait側は同じなので省略。
// traitTest.php use \PHPUnit\Framework\TestCase; use MyTrait; final class MyTreatTest extends TestCase { protected static $mock; protected static $class; public static function setUpBeforeClass() { self::$mock = (new class extends TestCase {})->getMockForTrait(MyTrait::class); self::$class = new \ReflectionClass(self::$mock); } /** * @dataProvider dp_PrivateMethod */ public function testPrivateMethod($argument) { $method = self::$class->getMethod("privateMethod"); $method->setAccessible(true); $this->assertTrue($method->invoke(self::$mock, $argument)); } public function dp_PrivateMethod() { $mock = $this->getMockForTrait(MyTrait::class); $class = new \ReflectionClass(self::$mock); $method = $class->getMethod("anotherPrivateMethod"); $method->setAccessible(true); return [ "argument #1" => $method->invoke($mock, 1), "argument #2" => $method->invoke($mock, 2) ]; } }
メモ
- たぶんこれで動くと思うんですが、適当に抜き出したので万一動かなかったら大変申し訳ない。言われたら直します。
- getMockForTrait()
- ReflectionClass()
getMockForTrait()
はPHPUnit、ReflectionClass()
はPHPの標準機能getMockForTrait()
は文字通りTraitを受け取ってクラスっぽく展開するメソッド。ただしpublicスコープしか利用できないReflectionClass()
はクラスを受け取ってリバースエンジニアリングできたりするクラス。クラスが持ってるプロパティ・メソッドの一覧を出したり、本件みたいにprivateメソッドを外部から叩いたりできる
- テストしたいメソッドが1つだけなら
ReflectionMethod()
ってクラスのほうが楽そう。というかそっちを紹介する投稿のほうが多い。なんでだろうか setUp()
で初期化しないでsetUpBeforeClass()
でやりたいものだが、staticメソッドゆえ$this
が生えないので断念- 無名クラスを生やしてその場で殴ればselfに代入できる。黒魔術感はある。好みっぽい
- すべてのdataProviderは
setUpBeforeClass()
やsetUp()
よりも先に実行されるってご丁寧にNoteに書いてありました(リンク先のちょっと上)。そもClassの中に収めないで変数としてぶん投げといても悪くないんじゃなかろうか。
- すべてのdataProviderは
__construct()
でやりたいものだが、なんか失敗した()ので断念- テスト件数増えてくるとこの辺所要時間に響くかもしれない。要検討
- 無名クラスを生やしてその場で殴ればselfに代入できる。黒魔術感はある。好みっぽい
編集履歴
- 6 Nov. 2018
- dataProvider()の仕様についての話題を修正。
- 23 Sep. 2018
- setUpBeforeClass()でもできたので追記。
- dataProvider()での挙動を追記。
- 21 Sep. 2018
- 初版
以上