読者です 読者をやめる 読者になる 読者になる

ITの隊長のブログ

ITの隊長のブログです。CakePHPとPlayFrameworkを使って仕事しています。最近はAngular2をさわりはじめたお(^ω^ = ^ω^)

【CakePHP3.x】PhpStormにてPHPUnitをデバッグしたときのエラー

CakePHP3.x PHP

スポンサードリンク

環境

$ sw_vers 
ProductName:  Mac OS X
ProductVersion: 10.11.6
BuildVersion: 15G1212

'TMP'が定義されていない

Use of undefined constant TMP - assumed 'TMP'

なんぞこれ?

コードを追っていくと、下記コードでエラーが発生していた。

    // ...
    protected static function _defaultConfig($name)
    {
            $defaults = [
            'php' => [
                'cookie' => 'CAKEPHP',
                'ini' => [
                    'session.use_trans_sid' => 0,
                ]
            ],
            'cake' => [
                'cookie' => 'CAKEPHP',
                'ini' => [
                    'session.use_trans_sid' => 0,
                    'session.serialize_handler' => 'php',
                    'session.use_cookies' => 1,
                    'session.save_path' => TMP . 'sessions', // <- ここ
                    'session.save_handler' => 'files'
                ]
            ],
            // ...
    }
    // ...

要は、「"TMP"って定数が宣言されていないぞコラァー!」ってことだと思う。

過去こういうのでハマんなかったかな? ってことで思い出した。

www.aipacommander.com

そそ! これこれ。

$ ~/vendor/bin/phpunit --configuration ~/phpunit.xml.dist

./config/bootstra.php が見つからない

Warning Error: require_once(./config/bootstrap.php): failed to open stream: No such file or directory in ...

次はなにー?

<?php
    //...
    public function bootstrap()
    {
        require_once $this->configDir . '/bootstrap.php';
    }
    // ...

ここで発生している。

予備元を順に追っていきます。

<?php
    // ...
    public function run(ServerRequestInterface $request = null, ResponseInterface $response = null)
    {
        $this->app->bootstrap();
        // ...
<?php
    // ...
    public function execute($request)
    {
        try {
            $reflect = new ReflectionClass($this->_class);
            $app = $reflect->newInstanceArgs($this->_constructorArgs); // (´・ω・`)
        } catch (ReflectionException $e) {
            throw new LogicException(sprintf(
                'Cannot load "%s" for use in integration testing.',
                $this->_class
            ));
        }

        // Spy on the controller using the initialize hook instead
        // of the dispatcher hooks as those will be going away one day.
        EventManager::instance()->on(
            'Controller.initialize',
            [$this->_test, 'controllerSpy']
        );

        $server = new Server($app);
        $psrRequest = $this->_createRequest($request);
        $response = $server->run($psrRequest); // ここの中でbootstrap()を呼んでエラーが発生する

        return ResponseTransformer::toCake($response);
    }
    // ...

(´・ω・`)のところで、渡している値$this->_constructorArgsの中が、./configとなっているがダメ。

PhpStormのデバッグの設定では相対パスで設定すると何故かエラーになるので、絶対に変更しなければならない。

どうにかこいつの値を変更できないものか。と、調べていたら

<?php
    public function __construct($test, $class = null, $constructorArgs = null)
    {
        $this->_test = $test;
        $this->_class = $class ?: Configure::read('App.namespace') . '\Application';
        $this->_constructorArgs = $constructorArgs ?: ['./config']; // ここ
    }

__constructで、設定されていた。三項演算子なので、$constructorArgsの値がnullなのがダメ。

じゃあ、このクラスをオブジェクト化しているのはどこか。

<?php
    // ...
    protected function _makeDispatcher()
    {
        if ($this->_useHttpServer) {
            return new MiddlewareDispatcher($this, $this->_appClass, $this->_appArgs); // ここ
        }

        return new LegacyRequestDispatcher($this);
    }
    // ...

ふむう。じゃあ、この、$this->_appArgsってのはどこで設定されているのかなー。

<?php
    // ...
    public function configApplication($class, $constructorArgs)
    {
        $this->_appClass = $class;
        $this->_appArgs = $constructorArgs;
    }
    // ...

みつけたぁあああ!!

ってことは、このメソッドがあるクラスを継承しているテストクラスでそのまま呼べんじゃん!

ってことで、試す。

  • 自分のテストクラス
<?php
    // ...
    public function testIndex()
    {
        $path = '<絶対パス>';
        $this->configApplication(null, [$path]); // 配列で渡す
        $this->post('/schedule-api/get', $postData);
        // ...
    }

うまくいったぁああああああああ!!!!

うまくいったけど

って、ちょいまち。

そもそも、コマンドの引数でbootstrap.phpを指定できないのか? と、疑問に思った瞬間、記憶が戻ってきた。

www.aipacommander.com

$ ~/vendor/bin/phpunit --bootstrap ~/tests/bootstrap.php ~/tests/

(°ω°; マサカ...!?

・・・できませんでした。( ´ー`)フゥー...

いや、よくないけどね。

なんででしょー?

うーん。そもそも、設定するのが、configApplication()のメソッドなら、こいつをコールしている箇所を探せばいいはず。

$ grep 'configApplication' -r ~/vendor/
~/vendor/cakephp/cakephp/src/TestSuite/IntegrationTestCase.php:    public function configApplication($class, $constructorArgs)

Oh...

どこも呼んでないやん。

よくわからんが、とりあえずconfigApplication()setup()で呼んで設定することにしました。

<?php
    // ...
    public function setUp()
    {
        $this->configApplication(null, [ROOT . 'config']);
        parent::setUp();
    }
    // ...