Mockery で overload かつ constant を使うために namedMock を直しました(プルリクはしてない
short answer:
github.com
long answer:
PHPUnitでCIとかに便利そうだからという理由だけで、モックフレームワークを使ってみることに。
MockerとPhakeで悩んだのですが、githubからアクティビティでMockeryにしてみました。(あと、githubのアイコンがカッコイイかr
github.com
インストールはcomposer.jsonを
{ "require-dev": { "phpunit/phpunit": "4.8.*", "mockery/mockery": "^0.9.5" } }
の
composer install
とかでいいはずです。(composerはhomebrewで入れたはず
あとはphpunit.xmlに
<phpunit backupGlobals="false" backupStaticAttributes="false" strict="true" verbose="true" bootstrap="phpunit_bootstrap.php"> <testsuites> <testsuite name="PHPUnit Test Suite"> <file>classes/utilities/XXXX_TestDriverTest.php</file> </testsuite> </testsuites> <logging> <log type="coverage-clover" target="logs/clover.xml"/> </logging> </phpunit>
<?php /** * Created by PhpStorm. * User: bhind * Date: 2016/10/05 * Time: 14:57 */ if (!defined('PHPUNIT_COMPOSER_INSTALL')) { define('PHPUNIT_COMPOSER_INSTALL', dirname(__FILE__) . '/vendor/autoload.php'); } require_once ('vendor/autoload.php'); $_SERVER["SYSTEM_ROOT"] = dirname(__FILE__) . '/../system/'; $_SERVER["WEBAPP_ROOT"] = dirname(__FILE__) . '/../'; $GLOBALS["_Log"] = new cLog(cLog::INFO); $GLOBALS["_DEBUG"] = true;
とかしておき、[PhpStorm]-[preference]-[Languages & Frameworks]-[PHP]-[PHPUnit]でautoloaderのpath to scriptを設定し、[Run]-[Edit Configuration]からTest Runner options:に -c でphpunit.xmlを指定します。
これで、[Run]からPHPUnitが起動できるはず。
さて、そこから何点かはまりました。
- なんか常にアプリのログが出て fail
logがdebugログ吐いてたのでlog levelをinfoにしました
- mockオブジェクトをoverload:をつけて作成しようとするとclass already existsとエラーで弾かれる
qiita.com
テストケースメソッドにアノテーション@runInSeparateProcess
アノテーションつけたらPHPUnitのクラスが見つからないいうからphpunit_bootstrap.phpに
<?php if (!defined('PHPUNIT_COMPOSER_INSTALL')) { define('PHPUNIT_COMPOSER_INSTALL', dirname(__FILE__) . '/vendor/autoload.php'); }
を追記。
autoloadでないrequireをテストケース内に移動
Mockeryのmockクラスのあとからrequire_onceで呼びに来る本番コードの方をclass_exists($class_name, false)でチェックするように(existsならrequireしない)
上記でほぼほぼ動くようになるのだが、今回のテストケースで最大の難関がCONSTが存在しないエラー…
overloadした本番コード側で返り値OKをみているところで、injectionされたmockにconstがなくてエラーになっていました。
下記をみると、const宣言したstubをnamedMockすればよいみたいにあるけど、、、
github.com
overload:をつけてnamedMockを呼ぶと
PHP Parse error: syntax error, unexpected ':', expecting '{' in /Users/..../vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php(16) : eval()'d code on line 25
とか言われました。コードを追ってみた結果、どうもMockery::namedMockでMockConfigurationBuilderを作りMockConfigurationBuilder::setNameして一般処理に流してるようなのだけど、その先のContainer::mockをみてみると本来行われるべき接頭辞処理がされてませんでした。なので、冒頭の変更はContainer::mockでやってる接頭辞処理をMockery::namedMockでするようにしただけです(しかもoverloadだけ)
そんなこんなで、テストケース一つにほぼ一日かかりました(´・ω・`)
<?php class ClassConstantStub { const OK = 0; } class XXXX_TestDriverTest extends PHPUnit_Framework_TestCase public function setUp() { } public function tearDown() { Mockery::close(); } /** * @runInSeparateProcess */ public function test_get_xxxx_code_master_id_from() { \Mockery::namedMock('overload:XXXXCodeMasterEntity', 'ClassConstantStub') ->shouldReceive('get_id')->andReturn(XXXXCodeMasterEntity::OK) ->andSet('xxx_code_master_id', 1)->andReturn(1); require_once ('XXXX_TestDriver.php'); $obj = new XXXX_TestDriver(); $method = $this->getMethod(get_class($obj), 'get_xxxx_code_master_id_from'); $args = array('xx_XX'); $expect = 1; $this->assertEquals($expect, $method->invokeArgs($obj,$args)); } protected function getMethod($className, $methodName) { $class = new ReflectionClass($className); $method = $class->getMethod($methodName); $method->setAccessible(true); return $method; } }