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>

して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とエラーで弾かれる

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;
    }
}
広告を非表示にする