LoginSignup
4
2

More than 5 years have passed since last update.

Mockery で overload かつ constant を使うために namedMock を直しました(プルリクはしてない

Posted at

この記事のコピーです。

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;
    }
}
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2