私はTDDを使用してプラグインを開発していますが、テストに失敗したことの1つは...フックです。
私は大丈夫、私はフックコールバックをテストすることができますが、フックが実際に起動するかどうかどうすればテストできますか(カスタムフックとWordPressデフォルトフックの両方)?私はいくらかのモックが役立つと思います、しかし私は単に私が欠けているものを理解することができません。
私はWP-CLIでテストスイートをインストールしました。 この答えによると 、init
フックは起動するはずですが、そうではありません。また、コードはWordPress内で機能します。
私の理解するところでは、ブートストラップは最後にロードされるので、initを起動しないことは一種の理にかなっています。それで、残る問題は次のとおりです。
ありがとうございます。
ブートストラップファイルは次のようになります。
$_tests_dir = getenv('WP_TESTS_DIR');
if ( !$_tests_dir ) $_tests_dir = '/tmp/wordpress-tests-lib';
require_once $_tests_dir . '/includes/functions.php';
function _manually_load_plugin() {
require dirname( __FILE__ ) . '/../includes/RegisterCustomPostType.php';
}
tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
require $_tests_dir . '/includes/bootstrap.php';
テスト済みファイルは次のようになります。
class RegisterCustomPostType {
function __construct()
{
add_action( 'init', array( $this, 'register_post_type' ) );
}
public function register_post_type()
{
register_post_type( 'foo' );
}
}
そしてテスト自体:
class CustomPostTypes extends WP_UnitTestCase {
function test_custom_post_type_creation()
{
$this->assertTrue( post_type_exists( 'foo' ) );
}
}
ありがとうございます。
プラグインを開発する場合、プラグインをテストする最良の方法は、WordPress環境をロードすることなくwithoutです。
WordPressなしで簡単にテストできるコードを作成すると、コードはbetterになります。
単体テストされるすべてのコンポーネントは、isolationでテストする必要があります。クラスをテストするときは、他のすべてのコードを想定して、その特定のクラスのみをテストする必要があります完璧に機能しています。
これが、単体テストが「ユニット」と呼ばれる理由です。
追加の利点として、コアをロードしなくても、テストがはるかに高速に実行されます。
私があなたに与えることができるヒントは、コンストラクターにフックを置くことを避けることです。これは、コードを単独でテスト可能にすることの1つです。
OPでテストコードを見てみましょう。
class CustomPostTypes extends WP_UnitTestCase {
function test_custom_post_type_creation() {
$this->assertTrue( post_type_exists( 'foo' ) );
}
}
そして、このテストfailsを想定してみましょう。 犯人は誰ですか?
クラスコードが次のとおりであるとします。
class RegisterCustomPostType {
function init() {
add_action( 'init', array( $this, 'register_post_type' ) );
}
public function register_post_type() {
register_post_type( 'foo' );
}
}
(注:残りの回答については、このバージョンのクラスを参照します)
このクラスを記述した方法では、add_action
を呼び出さずにクラスのインスタンスを作成できます。
上記のクラスには、テストするものが2つあります。
init
actuallyはadd_action
を呼び出し、適切な引数を渡しますregister_post_type
実際にがregister_post_type
関数を呼び出す投稿タイプが存在するかどうかを確認する必要があるとは言いませんでした。適切なアクションを追加し、register_post_type
を呼び出すと、カスタム投稿タイプmust存在する:存在しない場合は、WordPressの問題です。
注意:プラグインをテストするときは、WordPressコードではなく、yourコードをテストする必要があります。テストでは、WordPress(使用する他の外部ライブラリと同様)がうまく機能することを前提とする必要があります。それがunitテストの意味です。
WordPressがロードされていない場合、上記のクラスメソッドを呼び出そうとすると致命的なエラーが発生するため、関数をモックする必要があります。
モックライブラリを作成することも、すべてのメソッドを「手動で」モックすることもできます。それが可能だ。その方法を説明しますが、簡単な方法を紹介します。
テストの実行中にWordPressがロードされない場合、その機能を再定義できることを意味します。 add_action
またはregister_post_type
。
bootstrapファイルからロードされたファイルがあるとします。
function add_action() {
global $counter;
if ( ! isset($counter['add_action']) ) {
$counter['add_action'] = array();
}
$counter['add_action'][] = func_get_args();
}
function register_post_type() {
global $counter;
if ( ! isset($counter['register_post_type']) ) {
$counter['register_post_type'] = array();
}
$counter['register_post_type'][] = func_get_args();
}
関数が呼び出されるたびに、単純にグローバル配列に要素を追加するように関数を書き直しました。
ここで、PHPUnit_Framework_TestCase
:を拡張する独自のベーステストケースクラスを作成する必要があります(まだない場合)。これにより、テストを簡単に構成できます。
次のようになります。
class Custom_TestCase extends \PHPUnit_Framework_TestCase {
public function setUp() {
$GLOBALS['counter'] = array();
}
}
この方法では、すべてのテストの前に、グローバルカウンターがリセットされます。
そして今、あなたのテストコード(私は上記で投稿したrewrittenクラスを参照します):
class CustomPostTypes extends Custom_TestCase {
function test_init() {
global $counter;
$r = new RegisterCustomPostType;
$r->init();
$this->assertSame(
$counter['add_action'][0],
array( 'init', array( $r, 'register_post_type' ) )
);
}
function test_register_post_type() {
global $counter;
$r = new RegisterCustomPostType;
$r->register_post_type();
$this->assertSame( $counter['register_post_type'][0], array( 'foo' ) );
}
}
次のことに注意してください。
はい、すべてのWordPress関数を手動でモックする必要がある場合は、本当に苦痛です。私ができるいくつかの一般的なアドバイスは、できるだけ少ないWP関数を使用することです:WordPressをrewriteする必要はありませんが、abstractWPカスタムクラスで使用する関数。これにより、モックを作成して簡単にテストできます。
例えば。上記の例に関しては、投稿タイプを登録するクラスを作成し、指定された引数で「init」でregister_post_type
を呼び出すことができます。この抽象化では、まだそのクラスをテストする必要がありますが、投稿タイプを登録するコードの他の場所では、そのクラスを使用して、テストでモックすることができます(したがって、動作すると仮定します)。
素晴らしいことは、CPT登録を抽象化するクラスを作成する場合、そのための個別のリポジトリを作成でき、 Composer などの最新のツールのおかげで、必要なすべてのプロジェクトにそれを埋め込むことができます:一度テストし、everywhereを使用します。また、バグを見つけた場合は、1か所で修正することができ、単純なcomposer update
を使用して、使用されているすべてのプロジェクトも修正されます。
2回目:単独でテスト可能なコードを記述することは、より良いコードを記述することを意味します。
もちろん。コアと並行して行動するべきではありません、意味がありません。 WP関数をラップするクラスを作成できますが、それらのクラスもテストする必要があります。上記の「手動」メソッドは、非常に単純なタスクに使用できますが、クラスに多くのWP関数が含まれている場合、苦労する場合があります。
幸いなことに、そこには良いことを書く良い人がいます。 - 10up、最大のWP代理店の1つは、プラグインを正しい方法でテストします。 WP_Mock
です。
モックWP関数をフックにすることができます。テストにロードしたと仮定すると(レポREADMEを参照)、上で書いたものと同じテストがなります:
class CustomPostTypes extends Custom_TestCase {
function test_init() {
$r = new RegisterCustomPostType;
// tests that the action was added with given arguments
\WP_Mock::expectActionAdded( 'init', array( $r, 'register_post_type' ) );
$r->init();
}
function test_register_post_type() {
// tests that the function was called with given arguments and run once
\WP_Mock::wpFunction( 'register_post_type', array(
'times' => 1,
'args' => array( 'foo' ),
) );
$r = new RegisterCustomPostType;
$r->register_post_type();
}
}
簡単ですね。この答えはWP_Mock
のチュートリアルではないので、詳細についてはリポジトリのreadmeを読んでください。しかし、上記の例はかなり明確なはずです。
さらに、モックされたadd_action
やregister_post_type
を自分で書いたり、グローバル変数を維持したりする必要はありません。
WPにはいくつかのクラスもあり、テストの実行時にWordPressがロードされない場合、それらをモックする必要があります。
これは関数をモックするよりもはるかに簡単です。PHPUnitにはオブジェクトをモックする組み込みシステムがありますが、ここでは Mockery を提案します。これは非常に強力なライブラリであり、非常に使いやすいです。さらに、これはWP_Mock
の依存関係であるため、持っている場合はMockeryもあります。
WP_UnitTestCase
はどうですか?WordPressテストスイートは、WordPresscoreをテストするために作成され、コアに貢献したい場合これは極めて重要ですが、プラグインにそれを使用することで、単独ではなくテストすることができます。
WPの世界に目を向けてください。多くの最新のPHPフレームワークとCMSがあり、プラグイン/モジュール/拡張機能(またはそれらが呼び出されるもの)をテストすることを提案するものはありませんフレームワークコード。
スイートの便利な機能である工場を見逃した場合、 awesome things があることを知っておく必要があります。
ここで提案したワークフローに欠けている場合があります:カスタムデータベーステスト。
実際、標準のWordPressテーブルと関数を使用して(最低レベルの$wpdb
メソッドで)そこに書き込む場合、実際にデータを書き込む必要はありませんデータベース内のデータは実際にはです。適切な引数で適切なメソッドが呼び出されることを確認してください。
ただし、カスタムテーブルとプラグインを作成して、そこに書き込むクエリを作成し、それらのクエリが機能するかどうかをテストすることができます。
そのような場合、WordPressテストスイートは大いに役立ちます。また、dbDelta
などの関数を実行するために、WordPressのロードが必要になる場合があります。
(テストに別のデータベースを使用する必要はありませんよね?)
幸いなことに、PHPUnitを使用すると、個別に実行できる「スイート」でテストを整理できるため、WordPress環境(またはその一部)をロードして残りのすべてを残すカスタムデータベーステスト用のスイートを作成できますテストWordPress-free。
モックを使用すると、データベースを処理せずに大部分のクラスを適切にテストできるように、できるだけ多くのデータベース操作を抽象化するクラスを作成してください。
第三に、単独で簡単にテスト可能なコードを書くことは、より良いコードを書くことを意味します。