「PHPUnitテストを書く」の版間の差分

提供:MoodleDocs
移動先:案内検索
編集の要約なし
編集の要約なし
 
(同じ利用者による、間の111版が非表示)
1行目: 1行目:
{{Moodle 2.3}}
各テストの開始時、自動的にリセットされて新しくインストールされた状態となります。


作成中です - [[利用者:Mitsuhiro Yoshida|Mitsuhiro Yoshida]] ([[利用者・トーク:Mitsuhiro Yoshida|トーク]])
=ネームスペース=
 
*/testsディレクトリ以下のすべてはネームスペースを使用する場合に[[コーディングスタイル#**/testsディレクトリ内のネームスペース|いくつかの簡単なルールに従う]]必要があります。これらはテストケース、フィクスチャ、ジェネレータ、そして、一般的にはこれらのディレクトリ内すべてのクラスに適用されます。ご覧ください! (要約 = **/classes ディレクトリに適用されるルールと100% 同じです)
各テストの開始時に自動的にリセットされて新しくインストールされた状態となります。
=テストケースクラス=
 
すべてのMoodle単体テストで使用できる3つの基本テストクラスがあります - basic_testcase、advanced_testcaseおよびprovider_testcaseです。各クラスファイルには1つのテストケースのみを置くことを強く推奨します。
=ネームスペース Namespaces=
;basic_testcase : データベースおよびdataroot、そしてPHPのグローバルを変更しない非常にシンプルなテストです。例えば公式のPHPUnitチュートリアルにある例を試すときに使用します。
All the stuff under **/tests directories is [[Coding style#Namespaces_within_.2A.2A.2Ftests_directories|subject to some simple rules]] when using namespaces. */testsディレクトリ以下のすべてのものは名前空間を使用する場合に[[コーディングスタイル#**/testsディレクトリ内のネームスペース|いくつかの簡単なルールに従う]]必要があります。They apply to test cases, fixtures, generators and, in general, any class within those directories. Take a look to them! (grand summary = 100% the same rules that are applied to **/classes directories).
;advanced_testcase : Moodleのコードを簡単にテストできるよう強化されたテストケースクラスです。
=Testcase classes=
;provider_testcase: [[プライバシーAPI|プライバシープロバイダ]]のテストを容易にするために拡張された拡張テストケースクラスです。4番目のテストケースクラスはMoodleデータベースレイヤのテスト用に特別に設計されているため、他の目的で使用しないでください。
There are three basic test class that are supposed to used in all Moodle unit tests - basic_testcase, advanced_testcase and provider_testcase. '''Please note it is strongly recommended to put only one testcase into each class file.'''
== アサーション Assertions ==
;basic_testcase : Very simple tests that do not modify database, dataroot or any PHP globals. It can be used for example when trying examples from the official PHPUnit tutorial.
アサーションに関する完全なリストは以下で確認できます。
;advanced_testcase : Enhanced testcase class enhanced for easy testing of Moodle code.
;provider_testcase: Enhanced testcase class, enhanced for easy testing of [[Privacy API|Privacy Providers]].
There is a fourth testcase class that is specially designed for testing of our Moodle database layer, it should not be used for other purposes.
== Assertions ==
The complete list of assertions can be found in the links below.
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
23行目: 18行目:
| Moodle 3.11
| Moodle 3.11
| PHPUnit 9.5
| PHPUnit 9.5
|[https://phpunit.readthedocs.io/en/9.5/assertions.html Documentation]
|[https://phpunit.readthedocs.io/en/9.5/assertions.html ドキュメンテーション]
|-
|-
| Moodle 3.10
| Moodle 3.10
| PHPUnit 8.5
| PHPUnit 8.5
|[https://phpunit.readthedocs.io/en/8.5/assertions.html Documentation]
|[https://phpunit.readthedocs.io/en/8.5/assertions.html ドキュメンテーション]
|-
|-
| Moodle 3.7 - 3.9
| Moodle 3.7 - 3.9
| PHPUnit 7.5
| PHPUnit 7.5
|[https://phpunit.readthedocs.io/en/7.5/assertions.html Documentation]
|[https://phpunit.readthedocs.io/en/7.5/assertions.html ドキュメンテーション]
|-
|-
| Moodle 3.4 - 3.6
| Moodle 3.4 - 3.6
| PHPUnit 6.5
| PHPUnit 6.5
|[https://phpunit.de/manual/6.5/en/assertions.html Documentation]
|[https://phpunit.de/manual/6.5/en/assertions.html ドキュメンテーション]
|}
|}
==Sample plugin testcase==
==サンプルプラグインテストケース==
PHPUnit tests are located in <tt>tests/*_test.php</tt> files in your plugin, for example <tt>mod/myplugin/tests/sample_test.php</tt>, the file should contain only one class that extends <tt>advanced_testcase</tt>:
PHPUnit テストはプラグインのtests/*_test.phpファイル (例: mod/myplugin/tests/sample_test.php) に配置されます。このファイルにはadvanced_testcaseを継承したクラスを1つだけ含む必要があります。
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  namespace mod_myplugin;
  namespace mod_myplugin;
48行目: 43行目:
  }
  }
</syntaxhighlight>
</syntaxhighlight>
See [[PHPUnit integration#Class and file naming rules]] for more information.
詳細は[[PHPUnitインテグレーション#クラスおよびファイル命名規則]]をご覧ください。
==Inclusion of Moodle library files==
==Moodleライブラリファイルのインクルード==
If you want to include some Moodle library files you should always declare '''global $CFG'''. The reason is that testcase files may be included from non-moodle code which does not make the global $CFG available automatically.
あなたがいくつかのMoodleライブラリファイルをインクルードしたい場合、常に「global $CFG」を宣言する必要があります。これはテストケースファイルが自動的にグローバル$CFGを利用できない非Moodleコードからインクルードされる可能性があることが理由です。
==Automatic state reset==
==自動状態リセット==
By default after each test Moodle database and dataroot is automatically reset to the original state which was present right after installation. make sure to use $this->resetAfterTest() to indicate that the database or changes of standard global variables are expected.
各テストの後、デフォルトではMoodleデータベースおよびdatarootは自動的にインストール直後の状態にリセットされます。データベースまたは標準グローバル変数の変更が予想される場合、$this->resetAfterTest()を使用してください


If you received the error "Warning: unexpected database modification, resetting DB state" it is because the test is not using <tt>$this->resetAfterTest()</tt>.
あなたが「Warning: unexpected database modification, resetting DB state」というエラーメッセージに遭遇した場合、テストが$this->resetAfterTest()を使用していないためだとお考えください。
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  namespace mod_myplugin;
  namespace mod_myplugin;
71行目: 66行目:
  }
  }
</syntaxhighlight>
</syntaxhighlight>
=Generators=
=ジェネレータ=
Tests that need to modify default installation may use generators to create new courses, users, etc. All examples on this page should be used from test methods of a test class derived from advanced_testcase.
デフォルトのインストールを修正する必要のあるテストでは新しいコースまたはユーザ等の作成にジェネレータを使用できます。このページのすべての例はadvanced_testcaseから派生したテストクラスのテストメソッドから使用する必要があります。
 
単体テストのパラメータにPHPUnit [https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers @dataProvider]関数を使用している場合、あなたはデータプロバイダ関数でデータジェネレータを使用またはユーザ等を変更できないことに留意してください。データプロバイダでは「データのインスタンス化/生成」しないでください'。ただ、定義のみしてください。そして、テスト本体ではインスタンス化/生成を進めれます。
 
==ユーザを作成する==
それぞれのテスト開始時にはゲストおよび管理者の2種類のユーザのみ存在します。あなたがさらにテストアカウントを追加する必要がある場合、以下を使用してください:


Note if you are using PHPUnit [https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers @dataProvider] functions to provide parameters to unit tests, you can not use the data generator or change the user etc in the data provider function. Data providers '''must not instantiate/create data'''. Just define it. And then, the test body can proceed with the instantiation/creation.
==Creating users==
At the start of each test there are only two users present - guest and administrator. If you need to add more test accounts use:
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  $user = $this->getDataGenerator()->create_user();
  $user = $this->getDataGenerator()->create_user();
</syntaxhighlight>
</syntaxhighlight>
You may also specify properties of the user account, for example:
あなたはユーザアカウントのプロパティも指定できます。例えば以下のようになります:
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  $user1 = $this->getDataGenerator()->create_user(array('email'=>'user1@example.com', 'username'=>'user1'));
  $user1 = $this->getDataGenerator()->create_user(array('email'=>'user1@example.com', 'username'=>'user1'));
</syntaxhighlight>
</syntaxhighlight>
By default no user is logged-in, use setUser() method to change current $USER value:
デフォルトではユーザはログインしていないため、 現在の$USER値を変更するにはsetUser()メソッドを使用してください:
 
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  $this->setUser($user1);
  $this->setUser($user1);
</syntaxhighlight>
</syntaxhighlight>
Guest and admin accounts have a shortcut methods:
ゲストおよび管理者アカウントにはショートカットメソッドがあります:
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  $this->setGuestUser();
  $this->setGuestUser();
  $this->setAdminUser();
  $this->setAdminUser();
</syntaxhighlight>
</syntaxhighlight>
Null can be used to set current user back to not-logged-in:
現在のユーザをログインなしにするためにNullを使用できます:
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  $this->setUser(null);
  $this->setUser(null);
</syntaxhighlight>
</syntaxhighlight>
==Creating course categories==
==コースカテゴリを作成する==
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  $category1 = $this->getDataGenerator()->create_category();
  $category1 = $this->getDataGenerator()->create_category();
  $category2 = $this->getDataGenerator()->create_category(array('name'=>'Some subcategory', 'parent'=>$category1->id));
  $category2 = $this->getDataGenerator()->create_category(array('name'=>'Some subcategory', 'parent'=>$category1->id));
</syntaxhighlight>
</syntaxhighlight>
==Creating courses==
==コースを作成する==
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  $course1 = $this->getDataGenerator()->create_course();
  $course1 = $this->getDataGenerator()->create_course();
109行目: 107行目:
  $course2 = $this->getDataGenerator()->create_course(array('name'=>'Some course', 'category'=>$category->id));
  $course2 = $this->getDataGenerator()->create_course(array('name'=>'Some course', 'category'=>$category->id));
</syntaxhighlight>
</syntaxhighlight>
==Creating activities==
==活動を作成する==
Some activity plugins include instance generators. The generator class are defined in plugindirectory/tests/generator/lib.php.
活動プラグインの中にはインスタンスジェネレータが含まれているものもあります。ジェネレータクラスはplugindirectory/tests/generator/lib.phpで定義されています。
 
以下、1ページのリソースで新しいコースを作成する例です:


Example of creation of new course with one page resource:
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  $course = $this->getDataGenerator()->create_course();
  $course = $this->getDataGenerator()->create_course();
118行目: 117行目:
  $generator->create_instance(array('course'=>$course->id));
  $generator->create_instance(array('course'=>$course->id));
</syntaxhighlight>
</syntaxhighlight>
The following is functionally the same, but a bit shorter:
以下、機能的には同じですが、少し短くなります:
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  $course = $this->getDataGenerator()->create_course();
  $course = $this->getDataGenerator()->create_course();
  $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
  $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
</syntaxhighlight>
</syntaxhighlight>
==Creating cohorts==
==コーホートを作成する==
{{Moodle 2.4}}
Moodle 2.4以降、データジェネレータは新しいコホートの作成に対応しています。
Since 2.4 there the data generator supports creation of new cohorts.
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  $cohort = $this->getDataGenerator()->create_cohort();
  $cohort = $this->getDataGenerator()->create_cohort();
</syntaxhighlight>
</syntaxhighlight>
==Simplified user enrolments==
==ユーザ登録の簡略化==
{{Moodle 2.4}}
標準の登録APIの代わりにデータジェネレータの簡易メソッドを使用できます。これは自己登録および手動登録プラグインと一緒に使用することを意図しています。
Instead of standard enrolment API it is possible to use simplified method in data generator. It is intended to be used with self and manual enrolment plugins.
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->enrol_user($userid, $courseid);
$this->getDataGenerator()->enrol_user($userid, $courseid);
137行目: 134行目:
$this->getDataGenerator()->enrol_user($userid, $courseid, $teacherroleid, 'manual');
$this->getDataGenerator()->enrol_user($userid, $courseid, $teacherroleid, 'manual');
</syntaxhighlight>
</syntaxhighlight>
==Creating scales==
==尺度を作成する==
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_scale();
$this->getDataGenerator()->create_scale();
$this->getDataGenerator()->create_scale(array('name' => $name, 'scale' => $scale, 'courseid' => $courseid, 'userid' => $userid, 'description' => description, 'descriptionformat' => $descriptionformat));
$this->getDataGenerator()->create_scale(array('name' => $name, 'scale' => $scale, 'courseid' => $courseid, 'userid' => $userid, 'description' => description, 'descriptionformat' => $descriptionformat));
</syntaxhighlight>
</syntaxhighlight>
==Creating roles==
==ロールを作成する==
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_role();
$this->getDataGenerator()->create_role();
$this->getDataGenerator()->create_role(array('shortname' => $shortname, 'name' => $name, 'description' => description, 'archetype' => $archetype));
$this->getDataGenerator()->create_role(array('shortname' => $shortname, 'name' => $name, 'description' => description, 'archetype' => $archetype));
</syntaxhighlight>
</syntaxhighlight>
==Creating tags==
==タグを作成する==
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_tag();
$this->getDataGenerator()->create_tag();
159行目: 156行目:
));
));
</syntaxhighlight>
</syntaxhighlight>
==Groups==
==グループ==
===Creating groups===
===グループを作成する===
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_group(array('courseid' => $courseid));
$this->getDataGenerator()->create_group(array('courseid' => $courseid));
$this->getDataGenerator()->create_group(array('courseid' => $courseid, 'name' => $name, 'description' => $description, 'descriptionformat' => $descriptionformat));
$this->getDataGenerator()->create_group(array('courseid' => $courseid, 'name' => $name, 'description' => $description, 'descriptionformat' => $descriptionformat));
</syntaxhighlight>
</syntaxhighlight>
===Adding users to groups===
===グループにユーザを追加する===
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_group_member(array('userid' => $userid, 'groupid' => $groupid));
$this->getDataGenerator()->create_group_member(array('userid' => $userid, 'groupid' => $groupid));
$this->getDataGenerator()->create_group_member(array('userid' => $userid, 'groupid' => $groupid, 'component' => $component, 'itemid' => $itemid));
$this->getDataGenerator()->create_group_member(array('userid' => $userid, 'groupid' => $groupid, 'component' => $component, 'itemid' => $itemid));
</syntaxhighlight>
</syntaxhighlight>
===Creating groupings===
===グルーピングを作成する===
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_grouping(array('courseid' => $courseid));
$this->getDataGenerator()->create_grouping(array('courseid' => $courseid));
$this->getDataGenerator()->create_grouping(array('courseid' => $courseid, 'name' => $name, 'description' => $description, 'descriptionformat' => $descriptionformat));
$this->getDataGenerator()->create_grouping(array('courseid' => $courseid, 'name' => $name, 'description' => $description, 'descriptionformat' => $descriptionformat));
</syntaxhighlight>
</syntaxhighlight>
===Adding groups to groupings===
===グルーピングにグループを追加する===
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_grouping_group(array('groupingid' => $groupingid, 'groupid' => $groupid));
$this->getDataGenerator()->create_grouping_group(array('groupingid' => $groupingid, 'groupid' => $groupid));
</syntaxhighlight>
</syntaxhighlight>
==Repositories==
==リポジトリ==
===Creating repository instances===
===リポジトリインスタンスを作成する===
{{Moodle 2.5}}
一部のリポジトリプラグインにはインスタンスジェネレータを含むものがあります。ジェネレータクラスは plugindirectory/tests/generator/lib.phpで定義されています。
Some respository plugins include instance generators. The generator class are defined in plugindirectory/tests/generator/lib.php..
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_repository($type, $record, $options);
$this->getDataGenerator()->create_repository($type, $record, $options);
</syntaxhighlight>
</syntaxhighlight>
===Creating repository types===
===リポジトリタイプを作成する===
{{Moodle 2.5}}
一部のリポジトリプラグインにはタイプジェネレータを含むものがあります。ジェネレータクラスはplugindirectory/tests/generator/lib.phpで定義されています。
Some respository plugins include type generators. The generator class are defined in plugindirectory/tests/generator/lib.php..
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_repository_type($type, $record, $options);
$this->getDataGenerator()->create_repository_type($type, $record, $options);
</syntaxhighlight>
</syntaxhighlight>
==Creating grades==
==評定を作成する==
===Grade categories===
===評定カテゴリ===
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_grade_category(array('courseid' => $courseid));
$this->getDataGenerator()->create_grade_category(array('courseid' => $courseid));
$this->getDataGenerator()->create_grade_category(array('courseid' => $courseid, 'fullname' => $fullname));
$this->getDataGenerator()->create_grade_category(array('courseid' => $courseid, 'fullname' => $fullname));
</syntaxhighlight>
</syntaxhighlight>
===Grade items===
===評定アイテム===
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_grade_item();
$this->getDataGenerator()->create_grade_item();
$this->getDataGenerator()->create_grade_item(array('itemtype' => $itemtype, 'itemname' => $itemname, 'outcomeid' => $outcomeid, 'scaleid' => $scaleid, 'gradetype' => $gradetype));
$this->getDataGenerator()->create_grade_item(array('itemtype' => $itemtype, 'itemname' => $itemname, 'outcomeid' => $outcomeid, 'scaleid' => $scaleid, 'gradetype' => $gradetype));
</syntaxhighlight>
</syntaxhighlight>
===Outcomes===
===アウトカム===
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->getDataGenerator()->create_grade_outcome();
$this->getDataGenerator()->create_grade_outcome();
$this->getDataGenerator()->create_grade_item(array('fullname' => $fullname));
$this->getDataGenerator()->create_grade_item(array('fullname' => $fullname));
</syntaxhighlight>
</syntaxhighlight>
==Other types of plugin==
==他のタイプのプラグイン==
{{Moodle 2.5}}
他のどのようなタイプのプラグインでもジェネレータを持てます。ジェネレータクラスではcomponent_generator_baseを継承する必要があります。そして、あなたは $mygenerator = $this->getDataGenerator()->get_plugin_generator($frankenstylecomponentname)でインスタンスを取得できます。
Any other type of plugin can have a generator. The generator class should extend component_generator_base, and then you can get an instance using $mygenerator = $this->getDataGenerator()->get_plugin_generator($frankenstylecomponentname);


For some types of plugin, like mod documented above, there may be a more specific class than component_generator_base to extend, like testing_module_generator. That will give a consistent set of method names to use. Otherwise, you can create whatever methods you like on your generator, to create the different things you need to work whith.
いくつかのタイプのプラグインのために上で文書化されたmodのように拡張するcomponent_generator_baseよりも、さらに特定のクラス、例えばtesting_module_generatorのようなクラスがあるかもしれません、そのクラスでは使用すべきメソッド名の一貫したセットが与えてあることでしょう。そうでなければ、あなたが作業する必要のある別のものを作成するためにジェネレータ上でどのようなメソッドでも好きなように作成できます。
=Long tests=
=長いテスト=
All standard test should execute as fast as possible. Tests that take a loner time to execute (>10s) or are otherwise expensive (such as querying external servers that might be flooded by all dev machines) should be execute only when PHPUNIT_LONGTEST is true. This constant can be set in phpunit.xml or directly in config.php.
標準的なテストはすべて可能な限り高速に実行されるべきです。実行に時間を要するもの (10秒以上) または負荷のかかるもの (たとえば外部のサーバへの問い合わせに開発マシンが殺到してしまった場合等) はPHPUNIT_LONGTESTがtrueの場合のみ実行されるようにしなければなりません。この定数はphpunit.xmlあるいはconfig.phpで直接設定できます。
=Large test data=
=長いテストデータ=
See advanced_testcase::createXMLDataSet() and advanced_testcase::createCsvDataSet() and related functions there for easier ways to manage large test data sets within files rather than arrays in code. See [[PHPUnit_integration#Extra_methods]]
大きなテストデータセットをコード内の配列としてではなく、ファイルとして簡単に管理する方法に関して、advanced_testcase::createXMLDataSet()、advanced_testcase::createCsvDataSet()および関連関数を参照してください。詳細はPHPUnit_integration#Extra_methods]]を参照してください。
=Testing sending of messages=
=メッセージ送信テスト=
{{Moodle 2.4}}
あなたはmessage_send()で送信されたすべてのメッセージを一時的にメッセージシンクオブジェクトにリダイレクトできます。これにより開発者はテストしたコードが期待どおりのメッセージを送信しているかどうか確認できます。
You can temporarily redirect all messages sent via message_send() to a message sink object. This allows developers to verify that the tested code is sending expected messages.
 
メッセージングを使ったコードをテストする場合、まずトランザクションを無効にしてください。 メッセージングを新しいメッセージシンクにリダイレクトすることにより、 後で結果を確認できます。


To test code using messaging first disable the use of transactions and then redirect the messaging into a new message sink, you can inspect the results later.
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->preventResetByRollback();
$this->preventResetByRollback();
$sink = $this->redirectMessages();
$sink = $this->redirectMessages();
//... code that is sending messages
//... メッセージを送信するコード
$messages = $sink->get_messages();
$messages = $sink->get_messages();
$this->assertEquals(3, count($messages));
$this->assertEquals(3, count($messages));
//.. test messages were generated in correct order with appropriate content
//.. . テストメッセージが正しい順序および適切な内容で生成されました。
</syntaxhighlight>
</syntaxhighlight>
=Testing sending of emails=
=メール送信テスト=
{{Moodle 2.6}}
あなたはemail_to_user()で送信されたメールを一時的にメールメッセージシンクオブジェクトにリダイレクトできます。これにより、開発者はテストしたコードが期待とおりのメールを送信しているかどうかを確認できます。
You can temporarily redirect emails sent via email_to_user() to a email message sink object. This allows developers to verify that the tested code is sending expected emails.
 
メッセージングを使ったコードをテストする場合、まず「noemailever」の設定を解除してください。メールを新しいメッセージシンクにリダイレクトすることにより、 後で結果を確認できます。


To test code using messaging first unset 'noemailever' setting and then redirect the emails into a new message sink where you can inspect the results later.
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
unset_config('noemailever');
unset_config('noemailever');
242行目: 236行目:
$this->assertEquals(1, count($messages));
$this->assertEquals(1, count($messages));
</syntaxhighlight>
</syntaxhighlight>
=Logstores=
=ログストア=
You can test events which were written to a logstore, but you must disable transactions, enable at least one valid logstore, and disable logstore buffering to ensure that the events are written to the database before the tests execute.
あなたはログストアに書き込まれたイベントをテストできますが、テスト実行の前にイベントがデータベースに書き込まれるようトランザクションを無効にして、少なくとも1つの有効なログストアを有効にした上で、ログストアのバッファリングを無効にする必要があります。
 
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
$this->preventResetByRollback();
$this->preventResetByRollback();
250行目: 245行目:
get_log_manager(true);
get_log_manager(true);
</syntaxhighlight>
</syntaxhighlight>
=Check your coverage=
=あなたのカバレッジを確認する=
{{Moodle 3.7}}
PHPUnitには単体テストのコードカバレッジ情報を生成する機能があります。
PHPUnit has the ability to generate code coverage information for your unit tests.


Prior to Moodle 3.7, this coverage would load all files and generate coverage for everything regardless of whether that file could be covered at all, or whether it was intentionally covered.
Moodle 3.7以前、このカバレッジはすべてのファイルを読み込み、そのファイルが全くカバーできないかどうか、または意図的にカバーされているかどうかに関係なく、すべてに対してカバレッジを生成していました。


Since Moodle 3.7 the '''phpunit.xml''' configuration contains generated coverage include and exclude information for each component.
Moodle 3.7以降、「phpunit.xml」設定には各コンポーネントの生成されたカバレッジインクルードおよびエクスクルード情報が含まれています。
==Generating include and exclude configuration==
==インクルードおよびエクスクルード設定を生成する==
{{Moodle 3.11}}
あなたが書いているテストと一緒に<tt>coverage.php</tt>ファイルを作成することにより、どのファイルがカバレッジのためにチェックされるかプログラム的に記述できます。
You can programatically describe which files will be checked for coverage by creating a <tt>coverage.php</tt> file alongside the tests that you are writing.


Since Moodle 4.0, a default configuration is applied for all plugins and it is not necessary to supply a coverage.php unless you wish to cover additional files.
Moodle 4.0以降、デフォルト設定がすべてのプラグインに適用されるため、あなたが追加ファイルをカバーしたい場合を除き、coverage.phpを提供する必要はありません。


The <tt>coverage.php</tt> file allows you to list include and exclude files and folders within the component being
<tt>coverage.php</tt>ファイルではテスト対象のコンポーネントに含まれるファイルおよびフォルダを一覧表示できます。指定されたすべてのパスはテストされるコンポーネントからの相対パスです。例えば「mod_forum」を扱う場合、あなたのコードは「mod_forum」に置かれます。また、単体テストは「mod/forum/tests/example_test.php」にあります。カバレッジファイルは「mod/forum/tests/coverage.php」にあります。指定されたすべてのパスは「mod/forum」からの相対パスとなります。
tested. All paths specified are relative to the component being tested. For example, when working with '''mod_forum''' your
code will be in '''mod/forum''', and its unit tests will be in '''mod/forum/tests/example_test.php'''. The coverage file
for this would be in '''mod/forum/tests/coverage.php''' and all paths specified would be relative to '''mod/forum'''.


It is possible to specify a combination of included files, included folders, excluded files, and excluded folders. This would allow you, for example, to include the entire '''classes''' directory, but exclude.a specific file or folder within it.
含まれるファイル、含まれるフォルダ、除外されるファイルおよび除外されるフォルダを組み合わせて指定できます。これにより、例えば「classes」ディレクトリ全体を含みながら、その中の特定のファイルまたはフォルダを除外できます。


The following is an example <tt>coverage.php</tt> file from '''mod_forum''':
以下「mod_forum」の<tt>coverage.php</tt>の例です:


Note: For Moodle versions 3.7 to 3.10, the [https://docs.moodle.org/dev/index.php?title=Writing_PHPUnit_tests&oldid=58177#Check_your_coverage syntax used] was slightly different.
メモ: Moodleバージョン3.7および3.10では[https://docs.moodle.org/dev/index.php?title=Writing_PHPUnit_tests&oldid=58177#Check_your_coverage 使用される文法]が少しだけ異なります。
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
return new class extends phpunit_coverage_info {
return new class extends phpunit_coverage_info {
291行目: 281行目:
};
};
</syntaxhighlight>
</syntaxhighlight>
Also, note that you can better define which class or function each test is effectively covering by using the <tt>@covers</tt> annotation as [https://phpunit.readthedocs.io/en/9.5/code-coverage-analysis.html#specifying-covered-code-parts described in the documention].
また、<tt>@covers</tt>アノテーションの使用により、各テストがどのクラスまたは関数を効果的にカバーしているか、より明確に定義できることに留意してください。詳細は[https://phpunit.readthedocs.io/en/9.5/code-coverage-analysis.html#specifying-covered-code-parts ドキュメンテーション]をご覧ください。


Since Moodle 4.0, the following default configuration is applied:{{Moodle 4.0}}
Moodle 4.0以降、以下のデフォルト設定が適用されます:
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
return new class extends phpunit_coverage_info {
return new class extends phpunit_coverage_info {
318行目: 308行目:
};
};
</syntaxhighlight>
</syntaxhighlight>
If a coverage.php file already exists, then the defaults will be added to the values already defined.
すでにcoverage.phpファイルが存在する場合、定義済みの値にデフォルトが追加されます。
=Best practice=
=ベストプラクティス=
There are several best practices, suggestions, and things to avoid which you should consider when writing unit tests. Some of these are described below.
あなたが単体テストを書く場合に考慮すべきいくつかのベストプラクティス、提案、そして避けるべき点があります。そのいくつかを以下に説明します。
==Code coverage==
==コードカバレッジ==
PHPUnit has the ability to generate code coverage information for your unit tests and this is well supported since.Moodle 3.7. We recommend that you consider checking the coverage of your plugins when you write your code.
PHPUnitには単体テストのコードカバレッジ情報を生成する機能があり、Moodle 3.7からサポートされています。あなたがコードを書く場合、プラグインのカバレッジの確認を検討することをお勧めします。
 
[https://phpunit.readthedocs.io/en/9.5/annotations.html#appendixes-annotations-covers-tables-annotations PHPUnitドキュメンテーション]で説明されているように@coversアノテーションを明示的に設定することを推奨します。
 
==resetAfterTestの使用を最小限に留める==
上で説明した例の多くでは<syntaxhighlight lang="php">resetAfterTest</syntaxhighlight>という命名法を用いてテスト終了後にデータベースおよびファイルシステムをリセットしていますが、 必要がなければこれを使用しないのが理想的でしょう。
一般的に言えばモック可能で実際の修正を必要としないコードを書くことを目指すべきでしょう。resetAfterTestを使用した場合、テストの速度は低下してしまいます。


We recommend that you explicitly set the @covers annotation as described in the [https://phpunit.readthedocs.io/en/9.5/annotations.html#appendixes-annotations-covers-tables-annotations PHPUnit documentation].
==共有setUpおよびインスタンス変数の扱いに注意する==
==Keep use of resetAfterTest to a minimum==
あなたはPHPUnit のテストで以下の主な2つの理由のためインスタンス変数の作成方法および使用方法に注意する必要があります:
Although many of the examples described above use the <syntaxhighlight lang="php">resetAfterTest</syntaxhighlight> nomenclature to reset the database and filesystem after your test completes, you should ideally not use this unless you have to.
# あなたがsetUpでフィクスチャを作成またはresetAfterTest関数をコールした場合、 そのフィクスチャおよび条件はテストスイートのすべてのテストに適用されます。これら条件を満たさないテストをスイートに追加した場合、 その条件が満たされることはありません。これによりテストが遅くなる場合があります。
Generally speaking you should aim to write code which is mockable, and does not require real fixtures.
# PHPUnitは起動時に各テストケースのインスタンスを作成して、 テストが実行される間はそれを破棄しません。テストケース内のデータをインスタンスデータとして保存する場合、_entire suite_が終了するまでメモリに保存されます。これはセットアップされて積極的に破棄されないフィクスチャはガベージコレクションされずにメモリの肥大化に繋がることを意味します。ひどい場合にはメモリの枯渇に繋がる可能性があります。
Use of resetAfterTest will also slow your tests down.
==Be careful with shared setUp and instance variables==
You should be careful of how you create and use instance variables in PHPUnit tests for two main reasons:
# If you create any fixtures in the setUp, or call the resetAfterTest function, these fixtures and conditions will apply for _all_ tests in the testsuite. You will not be able to add another test to the suite which does not require these conditions without those conditions being fulfilled anyway. This can lead to slow tests.
# PHPUnit creates an instance of each testcase during its bootstrap phase, and does not dispose of it for the lifetime of the test run. Anything which causes data to be stored as instance data within the testcase will be stored in memory until the _entire suite_ completes. This means that any fixture which is setup and not actively discarded will not be garbage collected and lead to memory bloat. In severe cases this can lead to memory exhaustion.


データを生成およびresetAfterTestを設定するsetUpを含む既存のテストケースは段階的に廃止して、新しいケースを導入しないでください。


Existing testcases which contain setUp which either generate data, or set resetAfterTest should be phased out, and no new cases should be introduced.
==dataProvider関数を活用する==
==Make use of the dataProvider functionality==
PHPUnitのdataProvider機能は非常に強力で便利であり、 あなたは様々な条件で関数を素早く簡単に検証できます。
The dataProvider functionality of PHPUnit is an extremely powerful and useful feature which allows you to verify a function quickly and easily with a range of different conditions.
しかし、dataProvidersを使用する場合、以下のルールに従ってください:
However, the following rules should be followed when using dataProviders:
* resetAfterTestを必要とするリセット可能なデータの追加を最小限に抑えてください。
* Keep addition of resettable data requring resetAfterTest to a minimum - this will lead to many slow tests
* データプロバイダでは'''データをインスタンス化/生成しないでください'''。データを定義するのみにしてください。そして、テスト本体はインスタンス化/作成に進めます。データプロバイダはtestSuiteがインスタンス化された後、どのテストが実行される前にもコールされます。各テストは完全なsetUpおよびtearDownを実行して、作成されたデータはすべて破棄されます。
* Data providers '''must not instantiate/create data'''. Just define it. And then, the test body can proceed with the instantiation/creation. The dataProvider is called after the testSuite is instantiated, but before any tests are run. Each test will run a full setUp and tearDown, which will destroy any data which was created.
<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
/**
/**
371行目: 362行目:
}
}
</syntaxhighlight>
</syntaxhighlight>
=Extra test settings=
=追加テスト設定=
Usually the test should not interact with any external systems and it should work the same on all systems. But sometimes you need to specify some option for connection to external systems or system configuration. It is intentionally not possible to use $CFG settings from config.php.
通常、テストは外部システムとは連動せずに、どのシステムでも同じように動作する必要があります。しかし、時にはあなたは外部システムとの接続またはシステム構成のために何らかのオプションを指定する必要があります。config.phpから$CFG設定を使用することは意図的に不可能です。
カスタム設定を追加するには以下のようにいくつかの方法があります:
* phpunit.xmlファイルでテスト設定定数を定義する。
* config.phpでテスト設定定数を定義する。
これらの定数はテストまたはプラグインのコードで使用できます。
 
=Moodle 3.11およびそれ以上で動作するよう単体テストをアップグレードする (PHPUnit 9.5)=
Moodle 3.11は'''PHPUnitは9.5'''にアップグレードされました (以前のバージョンでは8.5が使用されていました)。これはMoodle 3.11でサポートされるPHPのバージョン (7.3、7.4、[[MoodleおよびPHP|8.0]]) にテスト環境を合わせるためです (詳細はMDL-71036および関連する報告をご覧ください)。
 
既存のテストの多くはPHPUnit 9.5でもそのまま動作しますが、'''かなりの数の非推奨の警告''' (テストの出力では「W」) が表示されるはずです。これらの警告は次のPHPUnitのアップグレードですべてエラーになるため、'''可能な限り早く新しい対応するものに置き換えるべき'''でしょう。


There are several ways how to inject your custom settings:
PHPUnit 9.5での変更点については以下の資料をご覧ください:
* define test setting constants in your phpunit.xml file
* [https://thephp.cc/news/2020/02/migrating-to-phpunit-9 良記事] リリースの主要な変更点が説明されています。
* define test setting constants in your config.php
* [https://phpunit.de/announcements/phpunit-9.html PHPUnit 9リリースアナウンスメント]
These constants may be then used in your test or plugin code.
* 詳細変更履歴 (いずれも変更を必要とする修正を含んでいるため):  [https://github.com/sebastianbergmann/phpunit/blob/9.0.0/ChangeLog-9.0.md 9.0], [https://github.com/sebastianbergmann/phpunit/blob/9.1.0/ChangeLog-9.1.md 9.1], [https://github.com/sebastianbergmann/phpunit/blob/9.3.0/ChangeLog-9.3.md 9.3], [https://github.com/sebastianbergmann/phpunit/blob/9.5.0/ChangeLog-9.5.md 9.5]
=Upgrading unit tests to work with Moodle 3.11 and up (PHPUnit 9.5)=
* [https://phpunit.readthedocs.io/en/9.5/ 公式PHPUnitマニュアル]
{{Moodle 3.11}}
すべての'''実行すべき変更および置換'''の要約は[https://github.com/moodle/moodle/blob/e3a46964dc6d8ca1558c6e1e8dfdf3c1745eeaed/lib/upgrade.txt#L5-L65 lib/upgrade.txt]ファイルにあります。主なポイントは以下のとおりです:
* PHPUnit 8.5で非推奨となった変更点 (以下のセクションを参照) はすべて削除されたため、エラーが発生するようになりました。
* assertContains()はより厳しく比較するようになりました (assertSame() のように)。新しいassertContainsEquals()が作成され、以前の挙動を提供します。
*<tt>phpunit.xml</tt>スキーマへの変更 (ほとんどが内部的なものです)。あなたがカスタム<tt>phpunit.xml</tt>ファイルを使用している場合のみ、これらが影響します。
** 前の<tt><filter></tt>セクションは現在 (良い意味で) <tt><coverage></tt>と呼ばれています。そして、その中では:
*** <tt><whitelist></tt>は<tt><include></tt>に置換されました。
*** <tt><exclude></tt>は<tt><whitelist></tt>の子ではなくなりました。代わりに<tt><coverage></tt>の子になりました。
** しかし、coverage.phpファイルで使用されていた<tt>$whitelistxxx</tt>プロパティが非推奨となったため、 [[#あなたのカバレッジを確認する|カバレッジ情報]]を定義する際には代わりに<tt>includelistfolders</tt>および<tt>includelistfiles</tt> (xmlの要素をより適切にマッピングするため) を使用するという意味があります。
* 警告: 個別のテストファイルは実行できないようになりました。実行したいテストを指定するには別の実行方法 (filter、suite、config) のいずれかを使用してください。これは最善の方法が合意された場合にMDL-71049で修正されることを期待しています。
* よく使われるアサーション: ファイルアサーション、正規表現アサーション、例外期待値等 ... これらはすべて次のPHPUnitのアップデートでエラーになることに注意してください。そのため、早急に更新することをお勧めします。


With Moodle 3.11, '''PHPUnit was upgraded to 9.5''' (from 8.5 being used in previous versions). This was done to '''better align''' the testing environment with PHP versions supported by Moodle 3.11 (7.3, 7.4 and [[Moodle and PHP|8.0]]) (see MDL-71036 and linked issues for more details).
最後に[https://github.com/moodle/moodle/compare/fc335f5...713722c 問題に関連する変更を点確認する]のも良いアイデアです。可能であればコミットメッセージに有用で十分な説明を添えてください。
=Moodle 3.10以降で動作するようにユニットテストをアップグレードする (PHPUnit 8.5)=


While a lot of existing tests will work without modification with PHPUnit 9.5, you will get a '''good number of deprecation warnings''' ("W" in the tests output) that '''should be replaced by their new counterparts as soon as possible''', because all those warnings will become errors with next PHPUnit upgrade.
Moodle 3.10ではPHPUnitが8.5にアップグレードされました (旧バージョンでは7.5が使用されていました)。これはMoodle 3.10でサポートされるPHPのバージョン (7.2、7.3および7.4) およびテスト環境の整合性を高めるため、およびMoodle 3.11 (php バージョン 7.3、7.4および 8.0) で必要となるPHPUnit 9.xへの移行を容易にして、多くの非推奨要素を事前に削除するために実施されました (MDL-67673およびMDL-64600を参照してください)。(詳細はMDL-67673およびMDL-64600を参照してください)。


To find more information about the changes coming with PHPUnit 9.5, it's recommended to read the following resources:
既存のテストの99%はPHPUnit 8.5でそのまま動作しますが、'''かなりの数の非推奨の警告''' ("W" が出力されます) が表示されます。これらの警告は次のPHPUnitアップグレードですべてエラーになるため、可能な限り早く解消すべきです。
* [https://thephp.cc/news/2020/02/migrating-to-phpunit-9 A good article] explaining all the main changes in the release.
* [https://phpunit.de/announcements/phpunit-9.html PHPUnit 9 release Announcement].
* These multiple detailed changelogs (because all them have included modifications requiring changes): [https://github.com/sebastianbergmann/phpunit/blob/9.0.0/ChangeLog-9.0.md 9.0], [https://github.com/sebastianbergmann/phpunit/blob/9.1.0/ChangeLog-9.1.md 9.1], [https://github.com/sebastianbergmann/phpunit/blob/9.3.0/ChangeLog-9.3.md 9.3], [https://github.com/sebastianbergmann/phpunit/blob/9.5.0/ChangeLog-9.5.md 9.5]
* [https://phpunit.readthedocs.io/en/9.5/ Official PHPUnit manual].
A good summary of all the '''changes and replacements to perform''' is available in the [https://github.com/moodle/moodle/blob/e3a46964dc6d8ca1558c6e1e8dfdf3c1745eeaed/lib/upgrade.txt#L5-L65 lib/upgrade.txt] file. With main points being:
* All the changes that were deprecated with PHPUnit 8.5 (see the section below) are now removed and will lead to errors.
* <tt>assertContains()</tt> now performs stricter comparison (like <tt>assertSame()</tt> does). New <tt>assertContainsEquals()</tt> has been created to provide the old behavior.
* Changes to the <tt>phpunit.xml</tt> schema, mostly internal. These only will impact if you are using custom <tt>phpunit.xml</tt> files:
** The previous <tt><filter></tt> section is now (better) called <tt><coverage></tt>. And, within it:
*** <tt><whitelist></tt> has been replaced by <tt><include></tt>.
*** <tt><exclude></tt> is not a child of <tt><whitelist></tt> anymore, but of <tt><coverage></tt>.
** But with implications when defining the [[#Check your coverage|coverage information]] because <tt>$whitelistxxx</tt> properties used by the <tt>coverage.php</tt> files have been deprecated, instead use <tt>includelistfolders</tt> and <tt>includelistfiles</tt> (to better map the elements in the xml).
* Warning: It's not possible to run individual test files any more. Use any of the alternative execution methods (filter, suite, config) to specify which tests you want to run. This will be hopefully fixed in MDL-71049 once it has been agreed which the best way to proceed is.
* Deprecations, deprecations, deprecations. Lots of them in often used assertions: file assertions, regexp assertions, exception expectations... again, note that all them will become errors with the next PHPUnit update, so '''the recommendation is to update them ASAP'''.
Finally, it's also a good idea to [https://github.com/moodle/moodle/compare/fc335f5...713722c browse the changes associated with the issue], hopefully with useful explanations in the commit messages.
=Upgrading unit tests to work with Moodle 3.10 and up (PHPUnit 8.5)=
{{Moodle 3.10}}


With Moodle 3.10, '''PHPUnit was upgraded to 8.5''' (from 7.5 being used in older version). This was done to '''better align''' the testing environment with PHP versions supported by Moodle 3.10 (7.2, 7.3 and 7.4) and also to provide an '''easier jump to PHPUnit 9.x''' that will be needed for Moodle 3.11 (php versions 7.3, 7.4 and 8.0), removing a lot of deprecated stuff in advance. (see MDL-67673 and MDL-64600 for more details).
PHPUnit 8.5での変更点に関して、以下のリソースをご覧ください:
* [https://thephp.cc/news/2019/02/help-my-tests-stopped-working 良記事] リリースの主要変更点すべてが説明されています。
* [https://phpunit.de/announcements/phpunit-8.html PHPUnit 8リリースアナウンスメント]
* [https://github.com/sebastianbergmann/phpunit/blob/130104cf796a88dd1547dc5beb8bd555c2deb55e/ChangeLog-8.0.md リリースの詳細変更ログ]
* [https://phpunit.readthedocs.io/en/8.5/ 公式PHPUnitマニュアル]
*すべての'''実行すべき変更および置換'''に関する分かりやすい要約は[https://github.com/moodle/moodle/blob/6594c54b2eef62499d304bfa0939999e3a14246e/lib/upgrade.txt#L5-L37 lib/upgrade.txt]ファイルにあります。主なポイントは以下のとおりです:
** すべてのテンプレートメソッド (setUp()、tearDown()) がvoidを返す必要があるようになったため、PHP 7.0のサポートは廃止されました。これはPHP 7.0をサポートするMoodleの古いブランチに対して同じテストを実行していたサードパーティプラグインのほとんどに影響が生じます。


While 99% of existing tests will work without modification with PHPUnit 8.5, you will get a '''good number of deprecation warnings''' ("W" in the tests output) that '''should be replaced by their new counterparts as soon as possible''', because all those warnings will become errors with next PHPUnit upgrade.
** <tt>PHPUnit/DBUnit</tt>は削除されて、軽い代替システムと置換されました。
** 多くはアサーション (<tt>assertContains()</tt>, <tt>assertEquals()</tt>...) および<tt>@expectedExceptionXXX</tt>アノテーションで使用されます。再度、これらすべてはPHPUnit 9でエラーとなることに留意してください。
* 最後に[https://github.com/moodle/moodle/compare/5903054...b13ec3c 課題に関連する変更点の閲覧]も良いアイデアです。可能であればコミットメッセージに有用で十分な説明を添えてください。


To find more information about the changes coming with PHPUnit 8.5, it's recommended to read the following resources:
=Moodle 3.7およびそれ以上で動作するよう単体テストをアップグレードする (PHPUnit 7.5)=
* [https://thephp.cc/news/2019/02/help-my-tests-stopped-working A good article] explaining all the main changes in the release.
* [https://phpunit.de/announcements/phpunit-8.html PHPUnit 8 release Announcement].
* [https://github.com/sebastianbergmann/phpunit/blob/130104cf796a88dd1547dc5beb8bd555c2deb55e/ChangeLog-8.0.md Detailed changelog of the release].
* [https://phpunit.readthedocs.io/en/8.5/ Official PHPUnit manual].
* A good summary of all the '''changes and replacements to perform''' is available in the [https://github.com/moodle/moodle/blob/6594c54b2eef62499d304bfa0939999e3a14246e/lib/upgrade.txt#L5-L37 lib/upgrade.txt] file. With main points being:
** Support for PHP 7.0 dropped (because all template methods (<tt>setUp()</tt>, <tt>tearDown()</tt>..) now require to return void. This will mostly impact 3rd-part plugins that were still running the same tests against old branches of Moodle with PHP 7.0 support.
** <tt>PHPUnit/DBUnit</tt> has been removed are replaced by a lightweight alternative.
** Deprecations, deprecations, deprecations. Lots of them in often used assertions (<tt>assertContains()</tt>, <tt>assertEquals()</tt>...) and also <tt>@expectedExceptionXXX</tt> annotations. Again, note that all them will become errors with PHPUnit 9.
* Finally, it's also a good idea to [https://github.com/moodle/moodle/compare/5903054...b13ec3c browse the changes associated with the issue], hopefully with useful enough explanations in the commit messages.
=Upgrading unit tests to work with Moodle 3.7 and up (PHPUnit 7.5)=
{{Moodle 3.7}}


With Moodle 3.7, '''PHPUnit was upgraded to 7.5''' (from 6.x being used in older version). This was done to better align the testing environment with PHP versions supported by Moodle 3.7 (7.1, 7.2 and 7.3). (see MDL-65204 and linked issues for more details). While internally [https://phpunit.de/announcements/phpunit-7.html a lot of things changed with PHPUnit 7] (PHP 7.1-isms, typed signatures, void returns, assertEquals() changes), thanks to our '''wrapping layer''' (basic and advanced testcases...) impact expected into old existing unit tests is expected to be reduced and upgrades, easy to achieve.
Moodle 3.7では'''PHPUnitが7.5'''にアップグレードされました (旧バージョンでは6.xが使用されていました)。これはMoodle 3.7 (7.1、7.2および7.3) でサポートされるPHPバージョンとテスト環境の整合性を高めるために実施されました (詳細はMDL-65204およびリンクされた問題をご覧ください)。内部的には[https://phpunit.de/announcements/phpunit-7.html PHPUnit 7で多くのことが変わりました] (PHP 7.1らしさ、型付きシグネチャ、 voidリターン、assertEquals()の変更) が我々の '''wrapping layer''' (基本および拡張テストケース ...) によって既存のユニットテストへの影響は少なく、アップグレードも簡単になると予想されます。


To find more information about the changes coming with PHPUnit 7, it's recommended to read the following resources:
PHPUnit 7での変更点に関して、以下のリソースをお読みください:
* [https://phpunit.de/announcements/phpunit-7.html  PHPUnit 7 release Announcement].
* [https://phpunit.de/announcements/phpunit-7.html  PHPUnit 7リリースアナウンスメント]
* [https://github.com/sebastianbergmann/phpunit/blob/520723129e2b3fc1dc4c0953e43c9d40e1ecb352/ChangeLog-7.5.md Detailed changelog of the release], paying special attention to the added, deprecated, changed and deleted sections.
* [https://github.com/sebastianbergmann/phpunit/blob/520723129e2b3fc1dc4c0953e43c9d40e1ecb352/ChangeLog-7.5.md リリースの詳細変更記録]です。特に追加、廃止、変更および削除セクションに注意を払ってください。
* [https://phpunit.readthedocs.io/en/7.5/ Official PHPUnit manual].
* [https://phpunit.readthedocs.io/en/7.5/ 公式PHPUnitマニュアル]
* Changes performed into core, mainly: new, stricter, signatures ([https://github.com/moodle/moodle/commit/26218b7 26218b7]) and assertEquals() changes, specially important when comparing strings, now performed using strict (===) equals ([https://github.com/moodle/moodle/commit/85f47ba 85f47ba]).
* コアに実施された修正点です。主に次のとおりです: new, stricter, signatures ([https://github.com/moodle/moodle/commit/26218b7 26218b7]) および assertEquals() に関する変更。特にストリングの比較時に重要です。現在、厳格な等号 (===) を使用して実行されます ([https://github.com/moodle/moodle/commit/85f47ba 85f47ba])
=Upgrading unit tests to work with Moodle 3.4 and up (PHPUnit 6)=
=Moodle 3.4およびそれ以上で動作するよう単体テストをアップグレードする (PHPUnit 6)=
{{Moodle 3.4}}
Moodle 3.4ではPHPUnitが6.4にアップグレードされました (旧バージョンでは5.5が使用されていました)。これはMoodle 3.4でサポートされるPHPのバージョン (7.0、7.1および7.2) およびテスト環境の整合性を高めるためです (詳細はMDL-60611およびリンクされた報告をご覧ください)。内部的には [https://github.com/sebastianbergmann/phpunit/wiki/Release-Announcement-for-PHPUnit-6.0.0#backwards-compatibility-issues PHPUnit 6で多くが変わりましたが]  (名前空間付きのクラスはより顕著です) 私たちの'''ラッピングレイヤ'''のおかげで (基本および高度なテストケース ...)  古い既存の単体テストへの影響は少なくなり、簡単にアップグレードもできるようになると思われます。


With Moodle 3.4, '''PHPUnit was upgraded to 6.4''' (from 5.5 being used in older version). This was done to better align the testing environment with PHP versions supported by Moodle 3.4 (7.0, 7.1 and 7.2). (see MDL-60611 and linked issues for more details). While internally [https://github.com/sebastianbergmann/phpunit/wiki/Release-Announcement-for-PHPUnit-6.0.0#backwards-compatibility-issues a lot of things changed with PHPUnit 6] (namespaced classes being the more noticeable), thanks to our '''wrapping layer''' (basic and advanced testcases...) impact expected into old existing unit tests is expected to be reduced and upgrades, easy to achieve.
しかし、特にphpuni のクラスを直接使用している場合、古い (3.4 以前) テストと新しいテスト間で互換性を維持できない場合があります。幸いなことにtravisおよびCIの両テストがこの状況を検出してくれるため、コアでサポートされているすべてのブランチを問題なく通過させるのは難しいことではないでしょう。プラグインの場合、同じブランチが複数のコアブランチに対して動作しようとしていて、それらがphpunitクラスを直接使用している場合、よりやっかいになるかもしれません。


Still, in '''some cases, it will impossible to maintain compatibility''' of tests between old (pre 3.4) tests and new ones, especially '''when direct use of any phpunit class is performed'''. Luckily, both travis and CI tests will detect this situation and it shouldn't be hard to keep all supported branches in core passing ok. Plugins may be trickier, if the same branch is attempting to work against multiple core branches and they are using some phpunit class directly.
PHPUnit 6での変更点に関して、以下のリソースをご覧ください:
* [https://thephp.cc/news/2017/02/migrating-to-phpunit-6 良記事] リリースの主要変更点すべてが説明されています。
* [https://github.com/sebastianbergmann/phpunit/wiki/Release-Announcement-for-PHPUnit-6.0.0#backwards-compatibility-issues PHPUnit 6リリースアナウンスメント]
* [https://github.com/sebastianbergmann/phpunit/blob/9d0c024d2099531442d862b66b0ad7cf35ed8e78/ChangeLog-6.0.md
リリースの詳細変更記録]です。特に変更および削除セクションに注意を払ってください。
* コアに実施された修正点です。主に次のとおり:  ネームスペースクラスのリネーム ([https://github.com/moodle/moodle/commit/801a372dadb6e11c8781547603e3f0a59ce5638f 801a372]) および廃止予定 ([https://github.com/moodle/moodle/commit/796e48a58bf18533bdca423fff7949ab119101c4 796e48a])


To find more information about the changes coming with PHPUnit 6, it's recommended to read the following resources:
=関連情報=
* [https://thephp.cc/news/2017/02/migrating-to-phpunit-6 A very good mini-guide] showing all the important changes.
* [[PHPUnitインテグレーション]]
* [https://github.com/sebastianbergmann/phpunit/wiki/Release-Announcement-for-PHPUnit-6.0.0#backwards-compatibility-issues PHPUnit 6 release Announcement].
* [https://github.com/sebastianbergmann/phpunit/blob/9d0c024d2099531442d862b66b0ad7cf35ed8e78/ChangeLog-6.0.md Detailed changelog of the release], paying special attention to the changed and deleted sections.
* Changes performed into core, mainly: namespace class renaming ([https://github.com/moodle/moodle/commit/801a372dadb6e11c8781547603e3f0a59ce5638f 801a372]) and deprecated stuff ([https://github.com/moodle/moodle/commit/796e48a58bf18533bdca423fff7949ab119101c4 796e48a])
=See also=
* [[PHPUnit integration]]
* [[PHPUnit]]
* [[PHPUnit]]
[[Category:Unit testing]]
[[Category:単体テスト]]


[[en:dev/Writing_PHPUnit_tests]]
[[en:dev/Writing_PHPUnit_tests]]

2022年8月5日 (金) 15:21時点における最新版

各テストの開始時、自動的にリセットされて新しくインストールされた状態となります。

ネームスペース

  • /testsディレクトリ以下のすべてはネームスペースを使用する場合にいくつかの簡単なルールに従う必要があります。これらはテストケース、フィクスチャ、ジェネレータ、そして、一般的にはこれらのディレクトリ内すべてのクラスに適用されます。ご覧ください! (要約 = **/classes ディレクトリに適用されるルールと100% 同じです)。

テストケースクラス

すべてのMoodle単体テストで使用できる3つの基本テストクラスがあります - basic_testcase、advanced_testcaseおよびprovider_testcaseです。各クラスファイルには1つのテストケースのみを置くことを強く推奨します。

basic_testcase
データベースおよびdataroot、そしてPHPのグローバルを変更しない非常にシンプルなテストです。例えば公式のPHPUnitチュートリアルにある例を試すときに使用します。
advanced_testcase
Moodleのコードを簡単にテストできるよう強化されたテストケースクラスです。
provider_testcase
プライバシープロバイダのテストを容易にするために拡張された拡張テストケースクラスです。4番目のテストケースクラスはMoodleデータベースレイヤのテスト用に特別に設計されているため、他の目的で使用しないでください。

アサーション Assertions

アサーションに関する完全なリストは以下で確認できます。

Moodle version PHPUnit version Links
Moodle 3.11 PHPUnit 9.5 ドキュメンテーション
Moodle 3.10 PHPUnit 8.5 ドキュメンテーション
Moodle 3.7 - 3.9 PHPUnit 7.5 ドキュメンテーション
Moodle 3.4 - 3.6 PHPUnit 6.5 ドキュメンテーション

サンプルプラグインテストケース

PHPUnit テストはプラグインのtests/*_test.phpファイル (例: mod/myplugin/tests/sample_test.php) に配置されます。このファイルにはadvanced_testcaseを継承したクラスを1つだけ含む必要があります。

 namespace mod_myplugin;

 class sample_test extends \advanced_testcase {
     public function test_adding() {
         $this->assertEquals(2, 1+2);
     }
 }

詳細はPHPUnitインテグレーション#クラスおよびファイル命名規則をご覧ください。

Moodleライブラリファイルのインクルード

あなたがいくつかのMoodleライブラリファイルをインクルードしたい場合、常に「global $CFG」を宣言する必要があります。これはテストケースファイルが自動的にグローバル$CFGを利用できない非Moodleコードからインクルードされる可能性があることが理由です。

自動状態リセット

各テストの後、デフォルトではMoodleデータベースおよびdatarootは自動的にインストール直後の状態にリセットされます。データベースまたは標準グローバル変数の変更が予想される場合、$this->resetAfterTest()を使用してください

あなたが「Warning: unexpected database modification, resetting DB state」というエラーメッセージに遭遇した場合、テストが$this->resetAfterTest()を使用していないためだとお考えください。

 namespace mod_myplugin;

 class test_something extends \advanced_testcase {
     public function test_deleting() {
         global $DB;
         $this->resetAfterTest(true);
         $DB->delete_records('user');
         $this->assertEmpty($DB->get_records('user'));
     }
     public function test_user_table_was_reset() {
         global $DB;
         $this->assertEquals(2, $DB->count_records('user', array()));
     }
 }

ジェネレータ

デフォルトのインストールを修正する必要のあるテストでは新しいコースまたはユーザ等の作成にジェネレータを使用できます。このページのすべての例はadvanced_testcaseから派生したテストクラスのテストメソッドから使用する必要があります。

単体テストのパラメータにPHPUnit @dataProvider関数を使用している場合、あなたはデータプロバイダ関数でデータジェネレータを使用またはユーザ等を変更できないことに留意してください。データプロバイダでは「データのインスタンス化/生成」しないでください'。ただ、定義のみしてください。そして、テスト本体ではインスタンス化/生成を進めれます。

ユーザを作成する

それぞれのテスト開始時にはゲストおよび管理者の2種類のユーザのみ存在します。あなたがさらにテストアカウントを追加する必要がある場合、以下を使用してください:

 $user = $this->getDataGenerator()->create_user();

あなたはユーザアカウントのプロパティも指定できます。例えば以下のようになります:

 $user1 = $this->getDataGenerator()->create_user(array('email'=>'user1@example.com', 'username'=>'user1'));

デフォルトではユーザはログインしていないため、 現在の$USER値を変更するにはsetUser()メソッドを使用してください:

 $this->setUser($user1);

ゲストおよび管理者アカウントにはショートカットメソッドがあります:

 $this->setGuestUser();
 $this->setAdminUser();

現在のユーザをログインなしにするためにNullを使用できます:

 $this->setUser(null);

コースカテゴリを作成する

 $category1 = $this->getDataGenerator()->create_category();
 $category2 = $this->getDataGenerator()->create_category(array('name'=>'Some subcategory', 'parent'=>$category1->id));

コースを作成する

 $course1 = $this->getDataGenerator()->create_course();
 
 $category = $this->getDataGenerator()->create_category();
 $course2 = $this->getDataGenerator()->create_course(array('name'=>'Some course', 'category'=>$category->id));

活動を作成する

活動プラグインの中にはインスタンスジェネレータが含まれているものもあります。ジェネレータクラスはplugindirectory/tests/generator/lib.phpで定義されています。

以下、1ページのリソースで新しいコースを作成する例です:

 $course = $this->getDataGenerator()->create_course();
 $generator = $this->getDataGenerator()->get_plugin_generator('mod_page');
 $generator->create_instance(array('course'=>$course->id));

以下、機能的には同じですが、少し短くなります:

 $course = $this->getDataGenerator()->create_course();
 $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id));

コーホートを作成する

Moodle 2.4以降、データジェネレータは新しいコホートの作成に対応しています。

 $cohort = $this->getDataGenerator()->create_cohort();

ユーザ登録の簡略化

標準の登録APIの代わりにデータジェネレータの簡易メソッドを使用できます。これは自己登録および手動登録プラグインと一緒に使用することを意図しています。

$this->getDataGenerator()->enrol_user($userid, $courseid);
$this->getDataGenerator()->enrol_user($userid, $courseid, $teacherroleid);
$this->getDataGenerator()->enrol_user($userid, $courseid, $teacherroleid, 'manual');

尺度を作成する

$this->getDataGenerator()->create_scale();
$this->getDataGenerator()->create_scale(array('name' => $name, 'scale' => $scale, 'courseid' => $courseid, 'userid' => $userid, 'description' => description, 'descriptionformat' => $descriptionformat));

ロールを作成する

$this->getDataGenerator()->create_role();
$this->getDataGenerator()->create_role(array('shortname' => $shortname, 'name' => $name, 'description' => description, 'archetype' => $archetype));

タグを作成する

$this->getDataGenerator()->create_tag();
$this->getDataGenerator()->create_tag(array(
    'userid' => $userid, 
    'rawname' => $rawname,
    'name' => $name, 
    'description' => $description, 
    'descriptionformat' => $descriptionformat,
    'flag' => $flag
));

グループ

グループを作成する

$this->getDataGenerator()->create_group(array('courseid' => $courseid));
$this->getDataGenerator()->create_group(array('courseid' => $courseid, 'name' => $name, 'description' => $description, 'descriptionformat' => $descriptionformat));

グループにユーザを追加する

$this->getDataGenerator()->create_group_member(array('userid' => $userid, 'groupid' => $groupid));
$this->getDataGenerator()->create_group_member(array('userid' => $userid, 'groupid' => $groupid, 'component' => $component, 'itemid' => $itemid));

グルーピングを作成する

$this->getDataGenerator()->create_grouping(array('courseid' => $courseid));
$this->getDataGenerator()->create_grouping(array('courseid' => $courseid, 'name' => $name, 'description' => $description, 'descriptionformat' => $descriptionformat));

グルーピングにグループを追加する

$this->getDataGenerator()->create_grouping_group(array('groupingid' => $groupingid, 'groupid' => $groupid));

リポジトリ

リポジトリインスタンスを作成する

一部のリポジトリプラグインにはインスタンスジェネレータを含むものがあります。ジェネレータクラスは plugindirectory/tests/generator/lib.phpで定義されています。

$this->getDataGenerator()->create_repository($type, $record, $options);

リポジトリタイプを作成する

一部のリポジトリプラグインにはタイプジェネレータを含むものがあります。ジェネレータクラスはplugindirectory/tests/generator/lib.phpで定義されています。

$this->getDataGenerator()->create_repository_type($type, $record, $options);

評定を作成する

評定カテゴリ

$this->getDataGenerator()->create_grade_category(array('courseid' => $courseid));
$this->getDataGenerator()->create_grade_category(array('courseid' => $courseid, 'fullname' => $fullname));

評定アイテム

$this->getDataGenerator()->create_grade_item();
$this->getDataGenerator()->create_grade_item(array('itemtype' => $itemtype, 'itemname' => $itemname, 'outcomeid' => $outcomeid, 'scaleid' => $scaleid, 'gradetype' => $gradetype));

アウトカム

$this->getDataGenerator()->create_grade_outcome();
$this->getDataGenerator()->create_grade_item(array('fullname' => $fullname));

他のタイプのプラグイン

他のどのようなタイプのプラグインでもジェネレータを持てます。ジェネレータクラスではcomponent_generator_baseを継承する必要があります。そして、あなたは $mygenerator = $this->getDataGenerator()->get_plugin_generator($frankenstylecomponentname)でインスタンスを取得できます。

いくつかのタイプのプラグインのために上で文書化されたmodのように拡張するcomponent_generator_baseよりも、さらに特定のクラス、例えばtesting_module_generatorのようなクラスがあるかもしれません、そのクラスでは使用すべきメソッド名の一貫したセットが与えてあることでしょう。そうでなければ、あなたが作業する必要のある別のものを作成するためにジェネレータ上でどのようなメソッドでも好きなように作成できます。

長いテスト

標準的なテストはすべて可能な限り高速に実行されるべきです。実行に時間を要するもの (10秒以上) または負荷のかかるもの (たとえば外部のサーバへの問い合わせに開発マシンが殺到してしまった場合等) はPHPUNIT_LONGTESTがtrueの場合のみ実行されるようにしなければなりません。この定数はphpunit.xmlあるいはconfig.phpで直接設定できます。

長いテストデータ

大きなテストデータセットをコード内の配列としてではなく、ファイルとして簡単に管理する方法に関して、advanced_testcase::createXMLDataSet()、advanced_testcase::createCsvDataSet()および関連関数を参照してください。詳細はPHPUnit_integration#Extra_methods]]を参照してください。

メッセージ送信テスト

あなたはmessage_send()で送信されたすべてのメッセージを一時的にメッセージシンクオブジェクトにリダイレクトできます。これにより開発者はテストしたコードが期待どおりのメッセージを送信しているかどうか確認できます。

メッセージングを使ったコードをテストする場合、まずトランザクションを無効にしてください。 メッセージングを新しいメッセージシンクにリダイレクトすることにより、 後で結果を確認できます。

$this->preventResetByRollback();
$sink = $this->redirectMessages();
//... メッセージを送信するコード
$messages = $sink->get_messages();
$this->assertEquals(3, count($messages));
//.. . テストメッセージが正しい順序および適切な内容で生成されました。

メール送信テスト

あなたはemail_to_user()で送信されたメールを一時的にメールメッセージシンクオブジェクトにリダイレクトできます。これにより、開発者はテストしたコードが期待とおりのメールを送信しているかどうかを確認できます。

メッセージングを使ったコードをテストする場合、まず「noemailever」の設定を解除してください。メールを新しいメッセージシンクにリダイレクトすることにより、 後で結果を確認できます。

unset_config('noemailever');
$sink = $this->redirectEmails();
//... code that is sending email
$messages = $sink->get_messages();
$this->assertEquals(1, count($messages));

ログストア

あなたはログストアに書き込まれたイベントをテストできますが、テスト実行の前にイベントがデータベースに書き込まれるようトランザクションを無効にして、少なくとも1つの有効なログストアを有効にした上で、ログストアのバッファリングを無効にする必要があります。

$this->preventResetByRollback();
set_config('enabled_stores', 'logstore_standard', 'tool_log');
set_config('buffersize', 0, 'logstore_standard');
get_log_manager(true);

あなたのカバレッジを確認する

PHPUnitには単体テストのコードカバレッジ情報を生成する機能があります。

Moodle 3.7以前、このカバレッジはすべてのファイルを読み込み、そのファイルが全くカバーできないかどうか、または意図的にカバーされているかどうかに関係なく、すべてに対してカバレッジを生成していました。

Moodle 3.7以降、「phpunit.xml」設定には各コンポーネントの生成されたカバレッジインクルードおよびエクスクルード情報が含まれています。

インクルードおよびエクスクルード設定を生成する

あなたが書いているテストと一緒にcoverage.phpファイルを作成することにより、どのファイルがカバレッジのためにチェックされるかプログラム的に記述できます。

Moodle 4.0以降、デフォルト設定がすべてのプラグインに適用されるため、あなたが追加ファイルをカバーしたい場合を除き、coverage.phpを提供する必要はありません。

coverage.phpファイルではテスト対象のコンポーネントに含まれるファイルおよびフォルダを一覧表示できます。指定されたすべてのパスはテストされるコンポーネントからの相対パスです。例えば「mod_forum」を扱う場合、あなたのコードは「mod_forum」に置かれます。また、単体テストは「mod/forum/tests/example_test.php」にあります。カバレッジファイルは「mod/forum/tests/coverage.php」にあります。指定されたすべてのパスは「mod/forum」からの相対パスとなります。

含まれるファイル、含まれるフォルダ、除外されるファイルおよび除外されるフォルダを組み合わせて指定できます。これにより、例えば「classes」ディレクトリ全体を含みながら、その中の特定のファイルまたはフォルダを除外できます。

以下「mod_forum」のcoverage.phpの例です:

メモ: Moodleバージョン3.7および3.10では使用される文法が少しだけ異なります。

return new class extends phpunit_coverage_info {
    /** @var array The list of folders relative to the plugin root to include in coverage generation. */
    protected $includelistfolders = [
        'classes',
        'externallib.php',
    ];

    /** @var array The list of files relative to the plugin root to include in coverage generation. */
    protected $includelistfiles = [];

    /** @var array The list of folders relative to the plugin root to exclude from coverage generation. */
    protected $excludelistfolders = [];

    /** @var array The list of files relative to the plugin root to exclude from coverage generation. */
    protected $excludelistfiles = [];
};

また、@coversアノテーションの使用により、各テストがどのクラスまたは関数を効果的にカバーしているか、より明確に定義できることに留意してください。詳細はドキュメンテーションをご覧ください。

Moodle 4.0以降、以下のデフォルト設定が適用されます:

return new class extends phpunit_coverage_info {
    /** @var array The list of folders relative to the plugin root to include in coverage generation. */
    protected $includelistfolders = [
        'classes',
        'tests/generator',
    ];

    /** @var array The list of files relative to the plugin root to include in coverage generation. */
    protected $includelistfiles = [
        'externallib.php',
        'lib.php',
        'locallib.php',
        'renderer.php',
        'rsslib.php',
    ];

    /** @var array The list of folders relative to the plugin root to exclude from coverage generation. */
    protected $excludelistfolders = [];

    /** @var array The list of files relative to the plugin root to exclude from coverage generation. */
    protected $excludelistfiles = [];
};

すでにcoverage.phpファイルが存在する場合、定義済みの値にデフォルトが追加されます。

ベストプラクティス

あなたが単体テストを書く場合に考慮すべきいくつかのベストプラクティス、提案、そして避けるべき点があります。そのいくつかを以下に説明します。

コードカバレッジ

PHPUnitには単体テストのコードカバレッジ情報を生成する機能があり、Moodle 3.7からサポートされています。あなたがコードを書く場合、プラグインのカバレッジの確認を検討することをお勧めします。

PHPUnitドキュメンテーションで説明されているように@coversアノテーションを明示的に設定することを推奨します。

resetAfterTestの使用を最小限に留める

上で説明した例の多くでは

resetAfterTest

という命名法を用いてテスト終了後にデータベースおよびファイルシステムをリセットしていますが、 必要がなければこれを使用しないのが理想的でしょう。

一般的に言えばモック可能で実際の修正を必要としないコードを書くことを目指すべきでしょう。resetAfterTestを使用した場合、テストの速度は低下してしまいます。

共有setUpおよびインスタンス変数の扱いに注意する

あなたはPHPUnit のテストで以下の主な2つの理由のためインスタンス変数の作成方法および使用方法に注意する必要があります:

  1. あなたがsetUpでフィクスチャを作成またはresetAfterTest関数をコールした場合、 そのフィクスチャおよび条件はテストスイートのすべてのテストに適用されます。これら条件を満たさないテストをスイートに追加した場合、 その条件が満たされることはありません。これによりテストが遅くなる場合があります。
  2. PHPUnitは起動時に各テストケースのインスタンスを作成して、 テストが実行される間はそれを破棄しません。テストケース内のデータをインスタンスデータとして保存する場合、_entire suite_が終了するまでメモリに保存されます。これはセットアップされて積極的に破棄されないフィクスチャはガベージコレクションされずにメモリの肥大化に繋がることを意味します。ひどい場合にはメモリの枯渇に繋がる可能性があります。

データを生成およびresetAfterTestを設定するsetUpを含む既存のテストケースは段階的に廃止して、新しいケースを導入しないでください。

dataProvider関数を活用する

PHPUnitのdataProvider機能は非常に強力で便利であり、 あなたは様々な条件で関数を素早く簡単に検証できます。 しかし、dataProvidersを使用する場合、以下のルールに従ってください:

  • resetAfterTestを必要とするリセット可能なデータの追加を最小限に抑えてください。
  • データプロバイダではデータをインスタンス化/生成しないでください。データを定義するのみにしてください。そして、テスト本体はインスタンス化/作成に進めます。データプロバイダはtestSuiteがインスタンス化された後、どのテストが実行される前にもコールされます。各テストは完全なsetUpおよびtearDownを実行して、作成されたデータはすべて破棄されます。
/**
 * Test function accepts parameters passed from the specified data provider.
 *
 * @dataProvider foobar_provider
 * @param int $foor
 * @param int $bar
 */
public function test_foobar(int $foo, int $bar) {
    // Perform the tests here.
}

/**
 * Data provider for {@see self::test_foobar()}.
 *
 * @return array List of data sets - (string) data set name => (array) data
 */
public function foobar_provider(): array {
    return [
        'Same numbers' => [
            'foo' => 42,
            'bar' => 42,
        ],
        'Different numbers' => [
            'foo' => 21,
            'bar' => 84,
        ],
    ];
}

追加テスト設定

通常、テストは外部システムとは連動せずに、どのシステムでも同じように動作する必要があります。しかし、時にはあなたは外部システムとの接続またはシステム構成のために何らかのオプションを指定する必要があります。config.phpから$CFG設定を使用することは意図的に不可能です。 カスタム設定を追加するには以下のようにいくつかの方法があります:

  • phpunit.xmlファイルでテスト設定定数を定義する。
  • config.phpでテスト設定定数を定義する。

これらの定数はテストまたはプラグインのコードで使用できます。

Moodle 3.11およびそれ以上で動作するよう単体テストをアップグレードする (PHPUnit 9.5)

Moodle 3.11はPHPUnitは9.5にアップグレードされました (以前のバージョンでは8.5が使用されていました)。これはMoodle 3.11でサポートされるPHPのバージョン (7.3、7.4、8.0) にテスト環境を合わせるためです (詳細はMDL-71036および関連する報告をご覧ください)。

既存のテストの多くはPHPUnit 9.5でもそのまま動作しますが、かなりの数の非推奨の警告 (テストの出力では「W」) が表示されるはずです。これらの警告は次のPHPUnitのアップグレードですべてエラーになるため、可能な限り早く新しい対応するものに置き換えるべきでしょう。

PHPUnit 9.5での変更点については以下の資料をご覧ください:

すべての実行すべき変更および置換の要約はlib/upgrade.txtファイルにあります。主なポイントは以下のとおりです:

  • PHPUnit 8.5で非推奨となった変更点 (以下のセクションを参照) はすべて削除されたため、エラーが発生するようになりました。
  • assertContains()はより厳しく比較するようになりました (assertSame() のように)。新しいassertContainsEquals()が作成され、以前の挙動を提供します。
  • phpunit.xmlスキーマへの変更 (ほとんどが内部的なものです)。あなたがカスタムphpunit.xmlファイルを使用している場合のみ、これらが影響します。
    • 前の<filter>セクションは現在 (良い意味で) <coverage>と呼ばれています。そして、その中では:
      • <whitelist><include>に置換されました。
      • <exclude><whitelist>の子ではなくなりました。代わりに<coverage>の子になりました。
    • しかし、coverage.phpファイルで使用されていた$whitelistxxxプロパティが非推奨となったため、 カバレッジ情報を定義する際には代わりにincludelistfoldersおよびincludelistfiles (xmlの要素をより適切にマッピングするため) を使用するという意味があります。
  • 警告: 個別のテストファイルは実行できないようになりました。実行したいテストを指定するには別の実行方法 (filter、suite、config) のいずれかを使用してください。これは最善の方法が合意された場合にMDL-71049で修正されることを期待しています。
  • よく使われるアサーション: ファイルアサーション、正規表現アサーション、例外期待値等 ... これらはすべて次のPHPUnitのアップデートでエラーになることに注意してください。そのため、早急に更新することをお勧めします。

最後に問題に関連する変更を点確認するのも良いアイデアです。可能であればコミットメッセージに有用で十分な説明を添えてください。

Moodle 3.10以降で動作するようにユニットテストをアップグレードする (PHPUnit 8.5)

Moodle 3.10ではPHPUnitが8.5にアップグレードされました (旧バージョンでは7.5が使用されていました)。これはMoodle 3.10でサポートされるPHPのバージョン (7.2、7.3および7.4) およびテスト環境の整合性を高めるため、およびMoodle 3.11 (php バージョン 7.3、7.4および 8.0) で必要となるPHPUnit 9.xへの移行を容易にして、多くの非推奨要素を事前に削除するために実施されました (MDL-67673およびMDL-64600を参照してください)。(詳細はMDL-67673およびMDL-64600を参照してください)。

既存のテストの99%はPHPUnit 8.5でそのまま動作しますが、かなりの数の非推奨の警告 ("W" が出力されます) が表示されます。これらの警告は次のPHPUnitアップグレードですべてエラーになるため、可能な限り早く解消すべきです。

PHPUnit 8.5での変更点に関して、以下のリソースをご覧ください:

  • 良記事 リリースの主要変更点すべてが説明されています。
  • PHPUnit 8リリースアナウンスメント
  • リリースの詳細変更ログ
  • 公式PHPUnitマニュアル
  • すべての実行すべき変更および置換に関する分かりやすい要約はlib/upgrade.txtファイルにあります。主なポイントは以下のとおりです:
    • すべてのテンプレートメソッド (setUp()、tearDown()) がvoidを返す必要があるようになったため、PHP 7.0のサポートは廃止されました。これはPHP 7.0をサポートするMoodleの古いブランチに対して同じテストを実行していたサードパーティプラグインのほとんどに影響が生じます。
    • PHPUnit/DBUnitは削除されて、軽い代替システムと置換されました。
    • 多くはアサーション (assertContains(), assertEquals()...) および@expectedExceptionXXXアノテーションで使用されます。再度、これらすべてはPHPUnit 9でエラーとなることに留意してください。
  • 最後に課題に関連する変更点の閲覧も良いアイデアです。可能であればコミットメッセージに有用で十分な説明を添えてください。

Moodle 3.7およびそれ以上で動作するよう単体テストをアップグレードする (PHPUnit 7.5)

Moodle 3.7ではPHPUnitが7.5にアップグレードされました (旧バージョンでは6.xが使用されていました)。これはMoodle 3.7 (7.1、7.2および7.3) でサポートされるPHPバージョンとテスト環境の整合性を高めるために実施されました (詳細はMDL-65204およびリンクされた問題をご覧ください)。内部的にはPHPUnit 7で多くのことが変わりました (PHP 7.1らしさ、型付きシグネチャ、 voidリターン、assertEquals()の変更) が我々の wrapping layer (基本および拡張テストケース ...) によって既存のユニットテストへの影響は少なく、アップグレードも簡単になると予想されます。

PHPUnit 7での変更点に関して、以下のリソースをお読みください:

Moodle 3.4およびそれ以上で動作するよう単体テストをアップグレードする (PHPUnit 6)

Moodle 3.4ではPHPUnitが6.4にアップグレードされました (旧バージョンでは5.5が使用されていました)。これはMoodle 3.4でサポートされるPHPのバージョン (7.0、7.1および7.2) およびテスト環境の整合性を高めるためです (詳細はMDL-60611およびリンクされた報告をご覧ください)。内部的には PHPUnit 6で多くが変わりましたが (名前空間付きのクラスはより顕著です) 私たちのラッピングレイヤのおかげで (基本および高度なテストケース ...) 古い既存の単体テストへの影響は少なくなり、簡単にアップグレードもできるようになると思われます。

しかし、特にphpuni のクラスを直接使用している場合、古い (3.4 以前) テストと新しいテスト間で互換性を維持できない場合があります。幸いなことにtravisおよびCIの両テストがこの状況を検出してくれるため、コアでサポートされているすべてのブランチを問題なく通過させるのは難しいことではないでしょう。プラグインの場合、同じブランチが複数のコアブランチに対して動作しようとしていて、それらがphpunitクラスを直接使用している場合、よりやっかいになるかもしれません。

PHPUnit 6での変更点に関して、以下のリソースをご覧ください:

リリースの詳細変更記録]です。特に変更および削除セクションに注意を払ってください。

  • コアに実施された修正点です。主に次のとおり: ネームスペースクラスのリネーム (801a372) および廃止予定 (796e48a)

関連情報