この記事のコピーです。
short answer:
fix an error of Mockery::namedMock with 'overload:' prefix. · bhind/mockery@c487ea3
long answer:
PHPUnitでCIとかに便利そうだからという理由だけで、モックフレームワークを使ってみることに。
MockerとPhakeで悩んだのですが、githubからアクティビティでMockeryにしてみました。(あと、githubのアイコンがカッコイイかr
padraic/mockery
インストールは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>
してphpunit_bootstrap.phpを
<?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とエラーで弾かれる
[http://qiita.com/kadoyau/items/13d515f42a943a6c6c1a:embed:cite]
テストケースメソッドにアノテーション@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すればよいみたいにあるけど、、、
MockeryでoverloadをつかってテストしたらCould not load mockとか言われる件
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;
}
}