test.phpスクリプトでMagento 2をブートストラップするにはどうすればよいですか?


93

magento 1では、Mage_Core_Model_Appクラスをインスタンス化するだけのファイルを作成し、テスト用に「ダーティ」コードを追加できました。
このようなものtest.php

<?php
//some settings
error_reporting(E_ALL | E_STRICT); 
define('MAGENTO_ROOT', getcwd()); 
$mageFilename = MAGENTO_ROOT . '/app/Mage.php'; 
require_once $mageFilename; 
Mage::setIsDeveloperMode(true); 
ini_set('display_errors', 1); 
umask(0);
//instantiate the app model
Mage::app(); 
//my toy code in here.

その後test.php、ブラウザーで呼び出して、自分が何をしているかを確認することができました。

Magento 2でも同じことができますか?


4
magento 2 cronはどのように機能しますか?同じアプローチを使用できますか?
アマスティ14年

4
良い考えですが、...からのコードcron.php$app = $bootstrap->createApplication('Magento\Framework\App\Cron', ['parameters' => ['group::']]);。独自のアプリモデルを作成する必要がありますか?
マリウス

1
ユニットテストを書く
クリストフ、フーマンで14年

2
@フーマン。回答としてこれを自由に書いてください、しかし例を提供してください。私はユニットテストに慣れていない。
マリウス

回答:


86

@Flyingmanaの回答に基づいて、少し掘り下げて解決策を考え出しました。私のために働くことは継ぎ目です。
最初に私の解決策、次にいくつかの説明。magentoインスタンスのルートで
呼び出されるファイルを作成しましたtest.php

<?php
require __DIR__ . '/app/bootstrap.php';
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
/** @var \Magento\Framework\App\Http $app */
$app = $bootstrap->createApplication('TestApp');
$bootstrap->run($app);

次にTestApp.php、このコンテンツと同じ場所で呼び出されるファイルを作成しました。

<?php
class TestApp
    extends \Magento\Framework\App\Http
    implements \Magento\Framework\AppInterface {
    public function launch()
    {
        //dirty code goes here. 
        //the example below just prints a class name
        echo get_class($this->_objectManager->create('\Magento\Catalog\Model\Category'));
        //the method must end with this line
        return $this->_response;
    }

    public function catchException(\Magento\Framework\App\Bootstrap $bootstrap, \Exception $exception)
    {
        return false;
    }

}

これtest.phpで、ブラウザで呼び出すことができ、TestApp :: launch()に配置されたすべてが実行されます。

さて、なぜこれが機能するのか:ブートストラップクラス
のメソッドcreateApplicationが最も重要な部分です。アプリケーションクラスのインスタンスを作成します。このメソッドcreateApplicationは、\Magento\Framework\AppInterface2つのメソッドを含むの実装を想定しています。
そこで、TestAppそのインターフェイスを実装する独自のクラスを作成しました。アプリに例外を処理させたくないので、メソッドを常にcatchException返すfalseようにしました。何か問題がある場合は、画面に印刷してください。
次に、メソッドを実装しましたlaunch。これはによって呼び出され\Magento\Framework\App\Bootstrap::runます。このrunメソッドは、アプリケーションがパラメーターとして渡したものに関係なく、ほぼ同じことを行います。
アプリケーションに依存する唯一のものは、次の行です。

$response = $application->launch();

これは、呼び出す\Magento\Framework\App\Bootstrap::runとMagento envが初期化され(他のクレイジーなことをするかもしれない...まだすべてをチェックしていない)launch、アプリケーションからメソッドを呼び出すことを意味します。
そのため、すべてのダーティコードをそのメソッド内に配置する必要があります。
その後\Magento\Framework\App\Bootstrap::runの呼び出しは$response->sendResponse();どこ$response何かlaunch方法が返されます。
それreturn $this->_response;が必要な理由です。空の応答を返すだけです。

\Magento\Framework\App\Httpリクエストとレスポンスのパラメーター(およびその他)が既にあるように、アプリクラスを拡張しましたが、クラスを拡張しないようにすることもできます。次に、\Magento\Framework\App\Httpクラスからコンストラクターをコピーする必要があります。必要に応じて、コンストラクタにパラメータを追加することもできます。


2
もちろん、TestApp同じtest.phpファイルでクラスを定義できたかもしれませんが、それほど汚くしたくありません:)
マリウス

「エリアコードが設定されていません」というエラーが表示されたためparent::launch();launch()メソッドの最初の行として追加する必要がありました
-OSdave

@OSdave。私がテストしたとき、それなしで機能しました。ほとんどの場合、最新バージョンで何かが変更されました。
マリウス

@Marius、サーバーのクイックインストールを実行してmagentoをインストールしました。また、アプリにbootstrap.phpがない
-er.irfankhan11

1
@Butterflyカスタムコントローラーに含める必要はありません。ファイルは、コントローラーに到達する前にindex.phpに含まれます。
マリウス

54

クイック/ショート/ダーティテストでは、次のようなものを使用しました。

use Magento\Framework\App\Bootstrap;
require __DIR__ . '/../app/bootstrap.php';

$bootstrap = Bootstrap::create(BP, $_SERVER);

$obj = $bootstrap->getObjectManager();

$state = $obj->get('Magento\Framework\App\State');
$state->setAreaCode('frontend');

$quote = $obj->get('Magento\Checkout\Model\Session')->getQuote()->load(1);
print_r($quote->getOrigData());

4
これは動作します。他の答えはそうではありません。
ahnbizcad

1
これは私の側でHTTP 500をトリガーします。
最大

2.1.2でも引き続き機能します。require-path thoを変更する必要がありました
simonthesorcerer

私のために動作しませんでした
サルファラージシパイ

20

@Mariusの答えに基づいて、私はこれを思いつきました。

コマンドラインとブラウザの両方を介して動作します。ブラウザは便利だと思います。

カテゴリをプログラムで削除するサンプルスクリプトを次に示します。

scripts/abstract.php

<?php
use \Magento\Framework\AppInterface as AppInterface;
use \Magento\Framework\App\Http as Http;

use Magento\Framework\ObjectManager\ConfigLoaderInterface;
use Magento\Framework\App\Request\Http as RequestHttp;
use Magento\Framework\App\Response\Http as ResponseHttp;
use Magento\Framework\Event;
use Magento\Framework\Filesystem;
use Magento\Framework\App\AreaList as AreaList;
use Magento\Framework\App\State as State;

abstract class AbstractApp implements AppInterface
{
    public function __construct(
        \Magento\Framework\ObjectManagerInterface $objectManager,
        Event\Manager $eventManager,
        AreaList $areaList,
        RequestHttp $request,
        ResponseHttp $response,
        ConfigLoaderInterface $configLoader,
        State $state,
        Filesystem $filesystem,
        \Magento\Framework\Registry $registry
    ) {
        $this->_objectManager = $objectManager;
        $this->_eventManager = $eventManager;
        $this->_areaList = $areaList;
        $this->_request = $request;
        $this->_response = $response;
        $this->_configLoader = $configLoader;
        $this->_state = $state;
        $this->_filesystem = $filesystem;
        $this->registry = $registry;
    }

    public function launch()
    {
        $this->run();
        return $this->_response;
    }

    abstract public function run();

    public function catchException(\Magento\Framework\App\Bootstrap $bootstrap, \Exception $exception)
    {
        return false;
    }
}

scripts/delete-category.php

<?php
require dirname(__FILE__) . '/../app/bootstrap.php';
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
require dirname(__FILE__) . '/abstract.php';

class CreateCategoriesApp extends AbstractApp
{

    public function run()
    {
        $this->_objectManager->get('Magento\Framework\Registry')
            ->register('isSecureArea', true);

        $category = $this->_objectManager->create('\Magento\Catalog\Model\Category');
        $category = $category->load(343);

        $category->delete();
    }
}

/** @var \Magento\Framework\App\Http $app */
$app = $bootstrap->createApplication('CreateCategoriesApp');
$bootstrap->run($app);

それから私はちょうどそれを実行します php scripts/delete-category.php


2
私は管理者コードにアクセスしたい場合は、それがエラーアクセスや地域の問題を示し、フロントエンドのために正常に動作し、あなたが管理エリアのために呼び出す方法を伝えることができます
プラディープ・クマール

何かを呼び出そうとすると、次のメッセージが表示されますMagento\Framework\Exception\LocalizedException: Area code is not set。どのように設定できますか?フロンドが必要です。
最大

このコードを書いて以来、M2をあまり見ていないのですが、フレームワークの変更によりM2が無効になったり修正が必要になったりする可能性があります。
ルークロジャース

18

要求されたとおり、テストを作成する方法の非常に短い例(フォルダー拡張構造に配置せずに)。残念ながら、これはすべてコマンドラインであり、ブラウザ経由での使用はできません。

ファイルを作成する

dev/tests/unit/quicktest.php

<?php

class QuickTest extends \PHPUnit_Framework_TestCase
{
    public function testExample()
    {
        //instantiate your class
        $context = new Magento\Framework\Object();

        $context->setData('param', 'value');

        //test whatever you want to test
        $this->assertEquals('value', $context->getData('param'));

        //you could even output to console
        echo $context->getData('param');

    }
}

次に、コードを実行するディレクトリdev/tests/unit/run からphpunit quicktest.php。ファイルdev/tests/unit/phpunit.xml.distは自動的にロードされ、環境を準備するため、これはすべて機能します。

多くの場合、クラスのコンストラクターに入力を提供する必要があります。dev/tests/unit/testsuite/オブジェクトのモックを含む、これがどのように見えるかのさらなる例については、既存のテストを参照してください。


1
私は「汚れた」遊び場を求めました。あなたはここにきれいなものを与えました:)。面白いアイデア。試してみます。
マリウス

7
過去にtest.phpを作成していた時代には、その努力が継続的な利益をもたらすテストの作成に費やされた可能性があります。
クリストフ、フーマンで14年

15

テストシステムに接続するよりも優れた方法を次に示します。Magento2のコマンドラインインターフェイスを使用します。

これは、実際のモジュールにサンドボックスコードを統合する(または目的のために作成する)必要があることを意味しますが、それでも実行する必要があります。

あなたのモジュールができたら設定しコマンドを追加することは非常に簡単です。必要なのは、クラスとそれを登録するためのDIだけです。

1. {モジュール} /etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\Console\CommandList">
        <arguments>
            <argument name="commands" xsi:type="array">
                <item name="greeting_command" xsi:type="object">Magento\CommandExample\Console\Command\GreetingCommand</item>
            </argument>
        </arguments>
    </type>
</config>

2. {モジュール} /Console/Command/GreetingCommand.php

<?php

namespace Magento\CommandExample\Console\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Class GreetingCommand
 */
class GreetingCommand extends Command
{
    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this->setName('example:greeting')
             ->setDescription('Greeting command');

        parent::configure();
    }

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln('<info>Hello world!</info>');
    }
}

https://github.com/magento/magento2-samples/tree/master/sample-module-commandから派生した例-この機能を組み込んだ完全なモジュールについては、こちらをご覧ください。あり、あまり些細な例含まれます。

慣例により、コマンドクラスは常にで{module}/Console/Command、末尾がである必要がありますCommand.php

これらの2ビットのコードを追加(およびMagentoのキャッシュなどをフラッシュ)したら、SSHで名前を指定してコマンドを実行しますphp bin/magento example:greeting

このコンテキストで依存性注入を使用できるので、内で必要なコードを実行できますexecute()

このインターフェイスはSymfonyのコンソールコンポーネント上に構築されているため、オプション/引数テーブル、非常に簡単なプログレスバーなど、その幅広い機能すべてに完全にアクセスできます。

コマンドまたはオプションの設定で問題が発生した場合、通常は「list」コマンドを実行して、問題の原因をよりよく把握できます。 php bin/magento list

楽しい。


いいね!Symfonyの大きなエクスポートのあるスクリプトの進行状況バーを使用します。ありがとう
アーバンサーファー

13

重要な部分は \Magento\Framework\App\Bootstrap::create

しかし、Bootstrap::init()メソッドはプライベートであり、多くの重要なことが起こるので、それを呼び出すパブリックメソッドが必要です。

片側のザッツcreateApplication()と、以下のrun()方法でなく、getDirList()そしてgetObjectManager()両方が引数を必要としない方法。

したがって、アプリケーションは必要ありませんが、欠点は、エラーHandlerが初期化されないことです。


6

トピックから外れている可能性もありますが、私は常に、Magento 1のContactsインデックスコントローラーファイルを使用してテストします(IndexActionメソッド)。example.com/contactsに行くのと同じくらい簡単です。これらの変更をコミットしないように注意する必要があります;)

Magento 2でも同様のことができると確信しています。ブートストラップコードを使用して新しいファイルを作成する必要はありません。


1
天国はあなたが忘れることを禁じているか、本番でそれをします!コアコードを変更しないでください。
ライアンホー

@RyanH。起こらない。バージョン管理、自動ビルド、静的コード分析、ピアコードレビュー、ステージング/ユーザー受け入れテスト/など。しかし、そうではない場合は、本番
環境で

1
それはあなたにとって素晴らしいことですが、ここで見ているほとんどの人はそのような種類のコントロールを持っていません。常に物事の正しい方法を教える(そして行う)ことをお勧めします。
ライアンホー

5

この回答は、マリウスによる上記の回答のわずかな修正です。

その理由は、Magento 2.1 Area code not setではそのコードを使用したときのようなエラーが発生したためです。So the intension of this answer is to fix that error on Magento 2.1

このエラーを修正するためにあなたがしなければならないことはあなたのエリアを定義することtest.php fileです。(以下の変更されたファイルを参照してください)。

<?php
require __DIR__ . '/app/bootstrap.php';
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
$obj = $bootstrap->getObjectManager();

$state = $obj->get('Magento\Framework\App\State');
$state->setAreaCode('frontend');
/** @var \Magento\Framework\App\Http $app */
$app = $bootstrap->createApplication('TestApp');
$bootstrap->run($app);

そして、TestApp.phpファイルは同じままです。

<?php

class TestApp
    extends \Magento\Framework\App\Http
    implements \Magento\Framework\AppInterface {
    public function launch()
    {
        //dirty code goes here.
        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $product = $objectManager->get('Magento\Catalog\Model\Product')->load(71);
        var_dump($product->getData());

        return $this->_response;
    }

    public function catchException(\Magento\Framework\App\Bootstrap $bootstrap, \Exception $exception)
    {
        return false;
    }

}

これも2.1.6では機能しません。Uncaught TypeError: Argument 2 passed to Magento\\Framework\\App\\Http::__construct() must be an instance of Magento\\Framework\\Event\\Manager, none given
ゲリラ

5

以下のコードを追加してmagentoルートにスクリプトを送信すると、ブートストラップが含まれます。[magentoルートフォルダーにtest.phpを作成し、以下のコードを含める]

ini_set('display_errors', 1);
ini_set('max_execution_time', 0);
ini_set("memory_limit", "-1");
set_time_limit(0);
error_reporting(E_ALL);
require './app/bootstrap.php';
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
$objectManager = $bootstrap->getObjectManager();
$state = $objectManager->get('Magento\Framework\App\State');
$state->setAreaCode('admin');

これが役に立てば幸いです。


2

以下のコードを使用して、Magento 2ルートから直接スクリプトを実行できます。Magento 2のルートディレクトリに新しいファイルを作成し、このコードを追加してから、ファイルにスクリプトを追加します。

<?php
    use Magento\Framework\App\Bootstrap;
    include('app/bootstrap.php');
    $bootstrap = Bootstrap::create(BP, $_SERVER);

    $objectManager = $bootstrap->getObjectManager();

    $state = $objectManager->get('Magento\Framework\App\State');
    $state->setAreaCode('frontend');

1

これは、Magentoディレクトリの外部のカスタムスクリプトにMagentoを初期化するために行ったことです。

//Required to include Magento functions.
$magento_dir "your/path/to/the/magento/installation/directory/";
require $magento_dir . 'app/bootstrap.php';
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
//$app = $bootstrap->createApplication('Magento\Framework\App\Http');
$app = $bootstrap->createApplication('MyClass');
$bootstrap->run($app);

これは、Magentoのドキュメントによると推奨される方法です。 http://devdocs.magento.com/guides/v2.0/config-guide/bootstrap/magento-bootstrap.html

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.