<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mackensen</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mackensen"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Mackensen"/>
	<updated>2026-07-16T12:00:59Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=PHPUnit&amp;diff=52520</id>
		<title>PHPUnit</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=PHPUnit&amp;diff=52520"/>
		<updated>2017-05-24T11:24:22Z</updated>

		<summary type="html">&lt;p&gt;Mackensen: /* LDAP */ clarify&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.3}}&lt;br /&gt;
&lt;br /&gt;
=What is PHPUnit=&lt;br /&gt;
PHPUnit by Sebastian Bergmann is an advanced unit testing framework for PHP. It is installed as Composer dependency and is not part of Moodle installation. To run PHPUnit tests, you have to manually install it on your development computer or test server.&lt;br /&gt;
&lt;br /&gt;
Read the excellent guide at&lt;br /&gt;
* [http://phpunit.de/manual/current/en/index.html PHPUnit Manual]&lt;br /&gt;
&lt;br /&gt;
=Installation of PHPUnit via Composer=&lt;br /&gt;
&lt;br /&gt;
Windows may require additional installation steps.&lt;br /&gt;
On Windows go to https://getcomposer.org/download/ and download the Composer-Setup.exe file&lt;br /&gt;
&lt;br /&gt;
* Execute Composer installer&lt;br /&gt;
&lt;br /&gt;
 cd /your/moodle/dirroot&lt;br /&gt;
 php composer.phar install&lt;br /&gt;
&lt;br /&gt;
(If that gives you connection problems try...)&lt;br /&gt;
&lt;br /&gt;
 php composer.phar install --prefer-source&lt;br /&gt;
&lt;br /&gt;
Troubleshooting:&lt;br /&gt;
* On Windows if you are behind a proxy you will need to setup an environment variable called HTTP_PROXY with a value detailing your HTTP Proxy address and port before composer will correctly download files.&lt;br /&gt;
* You may be prompted for github credentials when installing composer dependencies.&lt;br /&gt;
** This is used to generate an personal access token to avoid being rate limited by github.&lt;br /&gt;
** If you have Two Factor Authentication enabled on your github account, or do not wish to supply your own credentials you will need to generate a token manually:&lt;br /&gt;
*** Visit https://github.com/settings/applications and request personal access token&lt;br /&gt;
*** Copy this token and add it to your [https://gist.github.com/andrewnicols/c5377ed25a9df1006ce1 ~/.composer/config.json]&lt;br /&gt;
** ( See [https://github.com/composer/composer/issues/2280 composer issue #2280] for further details of this bug.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Detailed instructions:&lt;br /&gt;
* [http://getcomposer.org/doc/00-intro.md Composer documentation]&lt;br /&gt;
&lt;br /&gt;
Detailed instructions:&lt;br /&gt;
* [[PHPUnit installation in Windows]]&lt;br /&gt;
* [[PHPUnit installation in OS X]]&lt;br /&gt;
&lt;br /&gt;
== Uninstalling previous PEAR based version ==&lt;br /&gt;
&lt;br /&gt;
Before using composer, this page used to suggest to install phpunit via PEAR. If you did so, you may wish to uninstall that package now. This should work:&lt;br /&gt;
&lt;br /&gt;
   $ pear uninstall phpunit/DbUnit&lt;br /&gt;
   $ pear uninstall phpunit/PHPUnit&lt;br /&gt;
&lt;br /&gt;
=Initialisation of test environment=&lt;br /&gt;
&lt;br /&gt;
Our PHPUnit integration requires a dedicated database and dataroot.  First, add a new dataroot directory and prefix into your config.php, you can find examples in config-dist.php (scroll down to &#039;Section 9&#039;).&lt;br /&gt;
&lt;br /&gt;
 $CFG-&amp;gt;phpunit_prefix = &#039;phpu_&#039;;&lt;br /&gt;
 $CFG-&amp;gt;phpunit_dataroot = &#039;/home/example/phpu_moodledata&#039;;&lt;br /&gt;
&lt;br /&gt;
Some PHPUnit tests require a live internet connection. If your system does not have a direct connection to the Internet, you also need to specify your proxy in config.php - even though you normally specify it by using the admin settings user interface. (If you do not use a proxy, you can skip this step.) Check the settings on the relevant admin settings page, or from the mdl_config table in your database, if you are unsure of the correct values.&lt;br /&gt;
 &lt;br /&gt;
 // Normal proxy settings&lt;br /&gt;
 $CFG-&amp;gt;proxyhost = &#039;wwwcache.example.org&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxyport = 80;&lt;br /&gt;
 $CFG-&amp;gt;proxytype = &#039;HTTP&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxybypass = &#039;localhost, 127.0.0.1, .example.org&#039;;&lt;br /&gt;
 // Omit the next lines if your proxy doesn&#039;t need a username/password:&lt;br /&gt;
 $CFG-&amp;gt;proxyuser = &#039;systemusername&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxypassword = &#039;systempassword&#039;;&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.8.5 onwards, you can also provide specific database settings for unit testing (if these are not provided, the standard database settings will be used):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;$CFG-&amp;gt;phpunit_dbtype    = &#039;pgsql&#039;;      // &#039;pgsql&#039;, &#039;mariadb&#039;, &#039;mysqli&#039;, &#039;mssql&#039;, &#039;sqlsrv&#039; or &#039;oci&#039;&lt;br /&gt;
$CFG-&amp;gt;phpunit_dblibrary = &#039;native&#039;;     // &#039;native&#039; only at the moment&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbhost    = &#039;127.0.0.1&#039;;  // eg &#039;localhost&#039; or &#039;db.isp.com&#039; or IP&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbname    = &#039;mytestdb&#039;;     // database name, eg moodle&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbuser    = &#039;postgres&#039;;   // your database username&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbpass    = &#039;some_password&#039;;   // your database password&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you need to initialise the test environment using following command.&lt;br /&gt;
&lt;br /&gt;
 cd /home/example/moodle&lt;br /&gt;
 php admin/tool/phpunit/cli/init.php&lt;br /&gt;
&lt;br /&gt;
This command has to be repeated after any upgrade, plugin (un)installation or if you have added tests to a plugin you are developing:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; make sure that your php cli executable (or the one you want to use) is correctly on your path as the individual init scripts will call it repeatedly. Also, ensure en_AU locale is installed on your server.&lt;br /&gt;
&lt;br /&gt;
== LDAP ==&lt;br /&gt;
If you want to run LDAP unit tests you must have a working, configured LDAP environment on your test server. There must be a basic LDAP tree structure in place or tests will fail with &amp;quot;Search: No such object&amp;quot;. Build an LDAP tree structure in a new shell prompt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ ldapadd -H ldap://127.0.0.1 -D &amp;quot;cn=admin,dc=yourcomputer,dc=local&amp;quot; -W&lt;br /&gt;
dn:dc=yourcomputer,dc=local&lt;br /&gt;
objectClass:dcObject&lt;br /&gt;
objectClass:organizationalUnit&lt;br /&gt;
dc:yourcomputer&lt;br /&gt;
ou:YOURCOMPUTER&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In config.php tell Moodle where to look for your test LDAP environment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Constants for auth/ldap tests&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_HOST_URL&#039;, &#039;ldap://127.0.0.1&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_BIND_DN&#039;, &#039;cn=admin,dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_BIND_PW&#039;, &#039;*&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_DOMAIN&#039;, &#039;dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
&lt;br /&gt;
// Constants for lib/ldap tests&lt;br /&gt;
define(&#039;TEST_LDAPLIB_HOST_URL&#039;, &#039;ldap://127.0.0.1&#039;);&lt;br /&gt;
define(&#039;TEST_LDAPLIB_BIND_DN&#039;, &#039;cn=admin,dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
define(&#039;TEST_LDAPLIB_BIND_PW&#039;, &#039;*&#039;);&lt;br /&gt;
define(&#039;TEST_LDAPLIB_DOMAIN&#039;, &#039;dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Test execution=&lt;br /&gt;
&lt;br /&gt;
To execute all test suites from main configuration file execute the &amp;lt;code&amp;gt;vendor/bin/phpunit&amp;lt;/code&amp;gt; script from your &amp;lt;code&amp;gt;$CFG-&amp;gt;dirroot&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
&lt;br /&gt;
 cd /home/example/moodle&lt;br /&gt;
 vendor/bin/phpunit&lt;br /&gt;
&lt;br /&gt;
The rest of examples uses &amp;lt;code&amp;gt;phpunit&amp;lt;/code&amp;gt;, please substitute it with &amp;lt;code&amp;gt;vendor/bin/phpunit&amp;lt;/code&amp;gt; or create a shortcut in your dirroot.&lt;br /&gt;
&lt;br /&gt;
In IDEs, you may need to specify the path to the PHPUnit configuration file. Use the absolute path to &amp;lt;code&amp;gt;phpunit.xml&amp;lt;/code&amp;gt; from your &amp;lt;code&amp;gt;$CFG-&amp;gt;dirroot&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There is an alternative script for running of tests via web interface: &amp;lt;code&amp;gt;admin/tool/phpunit/webrunner.php&amp;lt;/code&amp;gt;. Use this as the last resort only when you cannot use the command-line interface on your test server. It will most probably break due to permissions problems if you try to execute it both from command-line and from webrunner. This feature is not officially supported.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===How to run only some tests===&lt;br /&gt;
&lt;br /&gt;
==== Running a single test quickly ====&lt;br /&gt;
&lt;br /&gt;
The fastest way to run a single test is:&lt;br /&gt;
&lt;br /&gt;
 vendor/bin/phpunit my_test_class_name my/tests/filename.php&lt;br /&gt;
&lt;br /&gt;
This is faster than other methods because it avoids the need to search for the test file, but you should be careful because it may be possible to run tests this way which are not included in the normal run. If you use this method, do at least one full test run (or --group run, as below) to ensure the test can be found.&lt;br /&gt;
&lt;br /&gt;
Please note the path name is optional if the testcase class and file names are standardised as described in [[Writing PHPUnit tests]].&lt;br /&gt;
&lt;br /&gt;
==== Using the @group annotation ====&lt;br /&gt;
&lt;br /&gt;
If you add annotations like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Unit tests for {@link stack_cas_keyval}.&lt;br /&gt;
 * @group qtype_stack&lt;br /&gt;
 */&lt;br /&gt;
class qtype_stack_cas_keyval_exception_testcase extends basic_testcase {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to all the classes in your plugin, then you can run just the tests for your plugin by doing&lt;br /&gt;
&lt;br /&gt;
 phpunit --group qtype_stack&lt;br /&gt;
&lt;br /&gt;
Therefore, it is suggested that you annotate all your tests with the Frankenstyle name of your plugin.&lt;br /&gt;
&lt;br /&gt;
==== Using multiple phpunit.xml files ====&lt;br /&gt;
&lt;br /&gt;
It&#039;s easy to create alternative phpunit.xml files defining which tests must be run together. For reference, take a look to the default /phpunit.xml available in your base directory once the testing environment has been initialised. After creating the custom file you will be able to run those tests with&lt;br /&gt;
&lt;br /&gt;
 vendor/bin/phpunit -c path/to/your/alternative/phpunit/file.xml&lt;br /&gt;
&lt;br /&gt;
Also, for commodity, you can use this command:&lt;br /&gt;
&lt;br /&gt;
 php admin/tool/phpunit/cli/util.php --buildcomponentconfigs&lt;br /&gt;
&lt;br /&gt;
It will, automatically, create one valid phpunit.xml file within each component (plugin or subsystem) and other important directories, so later you will be able to execute tests like&lt;br /&gt;
&lt;br /&gt;
 vendor/bin/phpunit -c mod/forum[/phpunit.xml]  // Note that it&#039;s not needed to specify the name of the file (if it is &#039;phpunit.xml&#039;).&lt;br /&gt;
 vendor/bin/phpunit -c question&lt;br /&gt;
 vendor/bin/phpunit -c question/type/calculated&lt;br /&gt;
 vendor/bin/phpunit -c backup&lt;br /&gt;
 vendor/bin/phpunit -c lib/dml&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
or, also&lt;br /&gt;
&lt;br /&gt;
 cd directory/with/phpunit.xml&lt;br /&gt;
 phpunit&lt;br /&gt;
&lt;br /&gt;
=External test resources=&lt;br /&gt;
{{Moodle 2.6}}&lt;br /&gt;
By default Moodle phpunit tests contact http://download.moodle.org server when testing curl related functionality. Optionally you may checkout a local copy of the test scripts and access it instead:&lt;br /&gt;
&lt;br /&gt;
# clone https://github.com/moodlehq/moodle-exttests to web directory&lt;br /&gt;
# add to your config.php or modify phpunit.xml file &amp;lt;code php&amp;gt;define(&#039;TEST_EXTERNAL_FILES_HTTP_URL&#039;, &#039;http://localhost/moodle-exttests&#039;);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing new tests=&lt;br /&gt;
* read [http://www.phpunit.de/manual/current/en/ official PHPUnit online documentation]&lt;br /&gt;
* see [[Writing PHPUnit tests]]&lt;br /&gt;
&lt;br /&gt;
=Conversion of existing SimpleTests=&lt;br /&gt;
* see [[SimpleTest conversion]]&lt;br /&gt;
&lt;br /&gt;
=PHPUnit support in IDEs=&lt;br /&gt;
&lt;br /&gt;
* [[Setting up Eclipse]]&lt;br /&gt;
* [[Setting up Netbeans]]&lt;br /&gt;
* [[Setting up PhpStorm]]&lt;br /&gt;
&lt;br /&gt;
=Common Unit Test Problems=&lt;br /&gt;
[[Common unit test problems]]&lt;br /&gt;
&lt;br /&gt;
=Performance=&lt;br /&gt;
&lt;br /&gt;
A typical run of full PHPUnit tests for Moodle 2.7 takes 10-20 minutes depending on the machine. If tests run slowly for you:&lt;br /&gt;
&lt;br /&gt;
* Ensure you are using a database and filesystem running on the same machine that is running the tests (not on a remote server).&lt;br /&gt;
* Apply developer-only performance settings to your database: [[Postgres Tuning For Developers]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Unit testing]]&lt;/div&gt;</summary>
		<author><name>Mackensen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Running_acceptance_test&amp;diff=52140</id>
		<title>Running acceptance test</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Running_acceptance_test&amp;diff=52140"/>
		<updated>2017-04-09T14:29:16Z</updated>

		<summary type="html">&lt;p&gt;Mackensen: add link to preconfigured vagrant profile&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Prerequisite ==&lt;br /&gt;
Before initializing acceptance test environment for running behat, you should ensure:&lt;br /&gt;
# [[Acceptance_testing#Requirements Meet min. system requirements for running tests]]&lt;br /&gt;
# [[Acceptance_testing#Installation Have set min. config variable in config.php for behat]]&lt;br /&gt;
# [[Acceptance_testing#Installation Downloaded composer dependencies]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
Acceptance tests (also known as behat), use [http://www.seleniumhq.org/download/ Selenium server] and can be run as:&lt;br /&gt;
# &#039;&#039;&#039;Single run:&#039;&#039;&#039; In single run, only one behat run is executed. So all features are executed in this single run.&lt;br /&gt;
# &#039;&#039;&#039;Parallel runs:&#039;&#039;&#039; (Since Moodle 3.0) Parallel runs allow dev&#039;s to execute multiple behat runs together. This was introduced to get acceptance tests results faster. To achieve this:&lt;br /&gt;
#* Features are divided between multiple behat runs&lt;br /&gt;
#* Symlinks behatrun{x} (x being the run process number), are created pointing to moodle directory, so site for run 1 is accessible via https://localhost/moodle/behatrun1&lt;br /&gt;
#* Process number is included as suffix to $CFG-&amp;gt;behat_prefix.&lt;br /&gt;
#* Process number is suffixed to $CFG-&amp;gt;behat_dataroot.&lt;br /&gt;
&lt;br /&gt;
== Step 1: Initialise acceptance test environment ==&lt;br /&gt;
Before running acceptance tests, environment needs to be initialised for acceptance testing.&lt;br /&gt;
&lt;br /&gt;
=== Single run ===&lt;br /&gt;
For initialising acceptance tests for single run, above command is sufficient.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/init.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parallel runs ===&lt;br /&gt;
For initialising acceptance tests for parallel runs, you can use one of the following options&lt;br /&gt;
# &#039;&#039;&#039;-j or --parallel&#039;&#039;&#039; (required) Number of parallel behat run to initialise&lt;br /&gt;
# &#039;&#039;&#039;-m or --maxruns&#039;&#039;&#039;  (optional) Max parallel site which should be initialised at one time. If your system is slow, then you can initialise sites in chucks.&lt;br /&gt;
# &#039;&#039;&#039;--fromrun&#039;&#039;&#039; (optional) Initialise site to run specified run from. Used for running acceptance tests on different vms&lt;br /&gt;
# &#039;&#039;&#039;--torun&#039;&#039;&#039; (optional) Initialise site to run specified run till. Used for running acceptance tests on different vms&lt;br /&gt;
# &#039;&#039;&#039;-o or --optimize-runs&#039;&#039;&#039; (optional) This option will split features with specified tags in all parallel runs, so they are executed first when parallel run gets executed.&lt;br /&gt;
# &#039;&#039;&#039;-a or --add-core-features-to-theme&#039;&#039;&#039; (optional) Since Moodle 3.2. Use this option to add all core features to specified theme&#039;s (comma separated list of themes)&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
// Below command will initialise moodle to run 2 parallel tests.&lt;br /&gt;
php admin/tool/behat/cli/init.php --parallel=2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Step 2: Running acceptance test environment ==&lt;br /&gt;
=== Single run ===&lt;br /&gt;
Run either of the following commands. For more options &#039;&#039;&#039;vendor/bin/behat --help&#039;&#039;&#039; or http://docs.behat.org/guides/6.cli.html&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
vendor/bin/behat --config /path/to/your/CFG_behat_dataroot/behatrun/behat/behat.yml&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/run.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parallel runs ===&lt;br /&gt;
For running parallel runs, use following command&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/run.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Following optional options are available for custom run:&lt;br /&gt;
# &#039;&#039;&#039;--feature&#039;&#039;&#039; Only execute specified feature file (Absolute path of feature file).&lt;br /&gt;
# &#039;&#039;&#039;--suite&#039;&#039;&#039; Features for specified theme will be executed.&lt;br /&gt;
# &#039;&#039;&#039;--replace&#039;&#039;&#039; Replace args string with run process number, useful for output and reruns.&lt;br /&gt;
# &#039;&#039;&#039;--fromrun&#039;&#039;&#039; Execute run starting from (Used for parallel runs on different vms)&lt;br /&gt;
# &#039;&#039;&#039;--torun&#039;&#039;&#039; Execute run till (Used for parallel runs on different vms)&lt;br /&gt;
# &#039;&#039;&#039;-a or --add-core-features-to-theme&#039;&#039;&#039; (optional) Since Moodle 3.2. Use this option to add all core features to specified theme&#039;s (comma separated list)&lt;br /&gt;
# Behat options can be passed for filtering features/scenarios:&lt;br /&gt;
#* In case you don&#039;t want to run Javascript tests, use the Behat tags option to skip them, &#039;&#039;&#039;--tags=&amp;quot;~@javascript&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
#* In case you want to run specific scenario, use the Behat name option to run it, &#039;&#039;&#039;--name=&amp;quot;Filter user accounts by role and cohort&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
#* In case you want to run specific feature file, use the Behat feature option to run it, &#039;&#039;&#039;--feature=&amp;quot;/PATH/TO/MOODLE/admin/tests/behat/filter_users.feature&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Common options for running tests ===&lt;br /&gt;
==== Tests filters ====&lt;br /&gt;
With the &#039;&#039;&#039;--tags&#039;&#039;&#039; or the &#039;&#039;&#039;-name&#039;&#039;&#039; Behat options you can filter which tests are going to run or which ones are going to be skipped. There are a few tags that you might be interested in:&lt;br /&gt;
* &#039;&#039;&#039;@javascript&#039;&#039;&#039;: All the tests that runs in a browser using Javascript; they require Selenium to be running, otherwise an exception will be thrown.&lt;br /&gt;
* &#039;&#039;&#039;@_file_upload&#039;&#039;&#039;: All the tests that involves file uploading or any OS feature that is not 100% part of the browser. They should only be executed when Selenium is running in the same machine where the tests are running.&lt;br /&gt;
* &#039;&#039;&#039;@_alert&#039;&#039;&#039;: All the tests that involves Javascript dialogs (alerts, confirms...) are using a feature that is OS-dependant and out of the browser scope, so they should be tag appropriately as not all browsers manage them properly.&lt;br /&gt;
* &#039;&#039;&#039;@_switch_window&#039;&#039;&#039;: All the tests that are using the &#039;&#039;&#039;I switch to &amp;quot;NAME&amp;quot; window&#039;&#039;&#039; step should be tagged as not all browsers manage them properly.&lt;br /&gt;
* &#039;&#039;&#039;@_switch_iframe&#039;&#039;&#039;: All the tests that are using the &#039;&#039;&#039;I switch to &amp;quot;NAME&amp;quot; window&#039;&#039;&#039; steps should be tagged as it is an advanced feature and some browsers may have problems dealing with them&lt;br /&gt;
* &#039;&#039;&#039;@_cross_browser&#039;&#039;&#039;: All the tests that should run against multiple combinations of browsers + OS in a regular basis. The features that are sensitive to different combinations of OS and browsers should be tagges as @_cross_browser.&lt;br /&gt;
* &#039;&#039;&#039;@componentname&#039;&#039;&#039;: Moodle features uses the [https://docs.moodle.org/dev/Frankenstyle Frankenstyle] component name to tag the features according to the Moodle subsystem they belong to.&lt;br /&gt;
&lt;br /&gt;
==== Output formats ====&lt;br /&gt;
Since Moodle 3.1 option for output is:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
--format=pretty --out=/path/to/pretty.txt --format=moodle_progress --out=std&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Before Moodle 3.1 option for output was:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
--format=&#039;moodle_progress,pretty&#039; --out=&#039;,/path/to/pretty.txt&#039;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Following output formats are supported:&lt;br /&gt;
# &#039;&#039;&#039;progress&#039;&#039;&#039;: Prints one character per step.&lt;br /&gt;
# &#039;&#039;&#039;pretty&#039;&#039;&#039;: Prints the feature as is.&lt;br /&gt;
# &#039;&#039;&#039;junit&#039;&#039;&#039;: Outputs the failures in JUnit compatible files.&lt;br /&gt;
# &#039;&#039;&#039;moodle_progress&#039;&#039;&#039;: Prints Moodle branch information and dots for each step.&lt;br /&gt;
# &#039;&#039;&#039;moodle_list&#039;&#039;&#039;: List all scenarios.&lt;br /&gt;
# &#039;&#039;&#039;moodle_stepcount&#039;&#039;&#039;: List all features with total steps in each feature file. Used for parallel run.&lt;br /&gt;
# &#039;&#039;&#039;moodle_screenshot&#039;&#039;&#039;: (since Moodle 3.1) Take screenshot and core dump of each step. With following options you can dump either or both.&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;image&amp;quot;}&#039;**: will dump image only&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;html&amp;quot;}&#039;**: will dump html only.&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;html,image&amp;quot;}&#039;**: will dump both.&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;html&amp;quot;, &amp;quot;dir_permissions&amp;quot;: &amp;quot;0777&amp;quot;}&#039;**&lt;br /&gt;
If you want to see the failures immediately (rather than waiting ~3 hours for all the tests to finish) then either use the -v option to output a bit more information, or change the output format using --format. Format &#039;pretty&#039; (&#039;&#039;&#039;-f pretty&#039;&#039;&#039;) is sufficient for most cases, as it outputs each step outcomes in the command line making easier to see the progress.&lt;br /&gt;
&lt;br /&gt;
== Advance usage ==&lt;br /&gt;
=== Rerun failed scenarios ===&lt;br /&gt;
With slow systems or parallel run you might see some random failures, to rerun only failed scenarios (to eliminate random failures), use --rerun option&lt;br /&gt;
# &#039;&#039;&#039;Single run:&#039;&#039;&#039; --run=&amp;quot;absolute_path_to_empty_file&amp;quot; (Behat will record failed scenarios in this file, and when run again only failed scenarios will be run)&lt;br /&gt;
# &#039;&#039;&#039;Parallel run:&#039;&#039;&#039; --rerun=&amp;quot;absolute_path_to_empty_file_{runprocess}.txt --replace=&amp;quot;{runprocess}&amp;quot; ({runprocess} will be replaced with the process number for recording fails in the specific run process).&lt;br /&gt;
&#039;&#039;&#039;Since Moodle 3.1 --rerun option don&#039;t accept any value, as it is handled internally by behat&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Running behat with specified theme (Since Moodle 3.2) ===&lt;br /&gt;
You can run behat with any theme installed. To execute behat with specified theme use &#039;&#039;&#039;--suite={THEME_NAME}&#039;&#039;&#039; option, while running behat. By default the features in theme behat folder will be executed for the suite. But if you want to run all core features with the specific theme then initialise acceptance test with -a option.&lt;br /&gt;
&lt;br /&gt;
==== Override behat core context for theme suite ====&lt;br /&gt;
To override behat step definitions so as to run behat with specified theme, you should create a contexts within &#039;&#039;&#039;/theme/{MYTHEME}/tests/behat/&#039;&#039;&#039; with prefix behat_theme_{MYTHEME}_ and suffixed with the context being overridden. For example, if you want to override behat_mod_forum context, then you should create a class /theme/{MYTHEME}/tests/behat/mod_forum/behat_theme_{MYTHEME}_behat_mod_forum.php&lt;br /&gt;
&lt;br /&gt;
==== Blacklist behat context or features to run in theme suite ====&lt;br /&gt;
To blacklist contexts/ features to be executed by theme suite you should create a /theme/{MYTHEME}/tests/behat/blacklist.json file with following format. Following will not use step_definitions from  behat_grade and behat_navigation while running theme suite. Also, scenarios in auth/tests/behat/login.feature and grade/tests/behat/grade_hidden_items.feature won&#039;t be executed with theme suite.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;contexts&amp;quot;: [&lt;br /&gt;
    &amp;quot;behat_grade&amp;quot;,&lt;br /&gt;
    &amp;quot;behat_navigation&amp;quot;,&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;features&amp;quot;: [&lt;br /&gt;
    &amp;quot;auth/tests/behat/login.feature&amp;quot;,&lt;br /&gt;
    &amp;quot;grade/tests/behat/grade_hidden_items.feature&amp;quot;,&lt;br /&gt;
   ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Override core behat selectors ====&lt;br /&gt;
To override behat selectors in specific theme, you should create a class behat_theme_{MYTHEME}_behat_selectors in /theme/{MYTHEME}/tests/behat/behat_theme_{MYTHEME}_behat_selectors.php extending behat_selectors.&lt;br /&gt;
&lt;br /&gt;
=== Use php built in web server ===&lt;br /&gt;
You can use php built-in-web server for executing behat runs. To do so:&lt;br /&gt;
# Open a command line interface and &#039;&#039;&#039;cd /to/your/moodle/dirroot&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;php -S localhost:8000&#039;&#039;&#039; (This is the test site URL that moodle uses by default, if you want to use another one you can override it in config.php with $CFG-&amp;gt;behat_wwwroot attribute; more info in https://docs.moodle.org/dev/Acceptance_testing#Advanced_usage or config-dist.php)&lt;br /&gt;
# Update $CFG-&amp;gt;behat_wwwroot = localhost:8000; in config.php&lt;br /&gt;
&lt;br /&gt;
=== Define custom options for parallel runs ===&lt;br /&gt;
You can set following custom config options for parallel runs via $CFG-&amp;gt;behat_parallel_run. It&#039;s an array of options where 1st array is for 1st run and so on.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
       array (&lt;br /&gt;
           &#039;dbtype&#039; =&amp;gt; &#039;mysqli&#039;,&lt;br /&gt;
           &#039;dblibrary&#039; =&amp;gt; &#039;native&#039;,&lt;br /&gt;
           &#039;dbhost&#039; =&amp;gt; &#039;localhost&#039;,&lt;br /&gt;
           &#039;dbname&#039; =&amp;gt; &#039;moodletest&#039;,&lt;br /&gt;
           &#039;dbuser&#039; =&amp;gt; &#039;moodle&#039;,&lt;br /&gt;
           &#039;dbpass&#039; =&amp;gt; &#039;moodle&#039;,&lt;br /&gt;
           &#039;behat_prefix&#039; =&amp;gt; &#039;mdl_&#039;,&lt;br /&gt;
           &#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4444/wd/hub&#039;,&lt;br /&gt;
           &#039;behat_wwwroot&#039; =&amp;gt; &#039;http://127.0.0.1/moodle&#039;,&lt;br /&gt;
           &#039;behat_dataroot&#039; =&amp;gt; &#039;/home/example/bht_moodledata&#039;&lt;br /&gt;
       )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To set different selenium servers for parallel runs, you can use following. NOTE: Running parallel (headless) runs on different selenium servers avoid random focus failures.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
    $CFG-&amp;gt;behat_parallel_run = array (&lt;br /&gt;
        array (&#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4444/wd/hub&#039;),&lt;br /&gt;
        array (&#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4445/wd/hub&#039;),&lt;br /&gt;
        array (&#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4446/wd/hub&#039;),&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running acceptance tests with different browser ===&lt;br /&gt;
By default behat will run with Firefox browser through Selenium. By adding the following code to your config.php you can change the selected browser that is run when behat is invoked.  You will need to run php admin/tool/behat/cli/init.php for changes to take effect. Then use --profile=&#039;chrome&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
$CFG-&amp;gt;behat_profiles = array(&lt;br /&gt;
   &#039;chrome&#039; =&amp;gt; array(&lt;br /&gt;
       &#039;browser&#039; =&amp;gt; &#039;chrome&#039;,&lt;br /&gt;
       &#039;tags&#039; =&amp;gt; &#039;@javascript&#039;,&lt;br /&gt;
       &#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4444/wd/hub&#039;,&lt;br /&gt;
       &#039;capabilities&#039; =&amp;gt; array(&lt;br /&gt;
           &#039;platform&#039; =&amp;gt; &#039;Linux&#039;&lt;br /&gt;
       )&lt;br /&gt;
   )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Acceptance_testing/Browsers|More info about alternative browsers]]&lt;br /&gt;
&lt;br /&gt;
=== Start multiple selenium servers ===&lt;br /&gt;
From command line Start selenium servers at different ports (say 4444, 4445, 4446 for 3 parallel runs)&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar -port 4444 &amp;amp;&lt;br /&gt;
java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar -port 4445 &amp;amp;&lt;br /&gt;
java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar -port 4446&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using Docker to start selenium server ===&lt;br /&gt;
==== What is Docker ====&lt;br /&gt;
Docker is a app container,  it&#039;s a kind of virtual machine, but only for one app, service,  so you can download&lt;br /&gt;
a docker image and run a selenium server without worry in how to configure selenium in your machine, one for chrome, others for firefox, you either don&#039;t need to install the browsers in your machine&lt;br /&gt;
To install docker follow this link; https://docs.docker.com/engine/installation/&lt;br /&gt;
&lt;br /&gt;
==== Selenium docker images ====&lt;br /&gt;
There is many docker images available,  for many browser, the complete list is in https://hub.docker.com/u/selenium/&lt;br /&gt;
for moodle you can use standalone version.&lt;br /&gt;
You can download  specific selenium version too,  for example,  for firefox,  moodle recommend selenium 2.53.1, see: [https://docs.moodle.org/dev/Acceptance_testing/Browsers/Working_combinations_of_OS%2BBrowser%2Bselenium What version do I need?]&lt;br /&gt;
&lt;br /&gt;
so  the command will be:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
docker run -d -p4444:4444 selenium/standalone-firefox:2.53.1-beryllium&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
to see all available version click in tags.   For firefox you can find at: https://hub.docker.com/r/selenium/standalone-firefox/tags/&lt;br /&gt;
&lt;br /&gt;
==== Change config.php file ====&lt;br /&gt;
In config.php file you must change the $CFG-&amp;gt;behat_wwwroot=   to your network card (NIC) ip address,  you can&#039;t use &lt;br /&gt;
localhost , 127.0.0.1, ...  or selenium docker server  will fail&lt;br /&gt;
&lt;br /&gt;
== NOTE ==&lt;br /&gt;
# Start the Selenium server (in case you want to run tests that involves Javascript)&lt;br /&gt;
#* (See http://www.installationpage.com/selenium/how-to-run-selenium-headless-firefox-in-ubuntu/ for running &#039;headless&#039; Firefox and xvfm in a server environment)&lt;br /&gt;
#* Open another command line interface and &#039;&#039;&#039;java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Trouble shooting ===&lt;br /&gt;
=== New step definitions or features are not executed === &lt;br /&gt;
If you are adding new tests or steps definitions update the tests list&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/util.php --enable&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039; For parallel runs, all options for initialising parallel runs are valid &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Tests are failing ===&lt;br /&gt;
If you followed all the steps and you receive an unknown weird error probably your system&#039;s Firefox version is not compatible with the Selenium version you are running.  Please refer Working combinations to ensure you have correct [[Acceptance_testing/Browsers/Working_combinations_of_OS%2BBrowser%2Bselenium combination]] of them to run acceptance test.&lt;br /&gt;
&lt;br /&gt;
=== Disable acceptance test environment ===&lt;br /&gt;
if you want to prevent access to test environment&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/util.php --disable&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that if you have the HTTP_PROXY environment variable set, which you may have had to do to run composer, then you also need to set NO_PROXY=localhost.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== External links ==&lt;br /&gt;
* Vagrant profile with Moodle and Behat preconfigured: https://github.com/mackensen/moodle-hat&lt;/div&gt;</summary>
		<author><name>Mackensen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Migrating_log_access_in_reports&amp;diff=50740</id>
		<title>Migrating log access in reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Migrating_log_access_in_reports&amp;diff=50740"/>
		<updated>2016-08-02T00:46:54Z</updated>

		<summary type="html">&lt;p&gt;Mackensen: unit test example&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is aimed to assist developers in replacing SQL queries that access the &#039;&#039;&#039;log&#039;&#039;&#039; table (now referred to as the &amp;quot;legacy log&amp;quot; for reports or other plugins.&lt;br /&gt;
&lt;br /&gt;
A new [[Logging 2|logging system]] is being introduced in Moodle 2.7. Writing to the legacy logging table may still be supported on some systems, however it is intended that administrators will make use of other logging plugins that can write to DB tables in the same DB as Moodle, to external DBs (SQL or non-SQL), to files, and so on. By default, a &#039;&#039;&#039;logstore_standard&#039;&#039;&#039; plugin is enabled that writes the data in the internal DB table. This table should not be queried directly. The new logging plugins define interfaces for reading data from the log stores.&lt;br /&gt;
&lt;br /&gt;
Reports also have the choice of accessing the active log stores via logging plugin reader interfaces or registering their own observers and storing necessary data themselves.&lt;br /&gt;
&lt;br /&gt;
== Using log readers ==&lt;br /&gt;
&lt;br /&gt;
First, reports need to find available log readers.&lt;br /&gt;
&lt;br /&gt;
There are three interfaces defined in core that log storage plugins may implement.&lt;br /&gt;
* &#039;&#039;&#039;\core\log\reader&#039;&#039;&#039; - parent for all reader interfaces;&lt;br /&gt;
* &#039;&#039;&#039;\core\log\sql_reader (\core\log\sql_select_reader in Moodle 2.7 and Moodle 2.8)&#039;&#039;&#039; - has methods to create simple SQL queries to the log store. The table (or equivalent storage collection) used is expected to have columns that correspond to properties of class &#039;&#039;&#039;\core\base\event&#039;&#039;&#039; and&lt;br /&gt;
* &#039;&#039;&#039;\core\log\sql_internal_table_reader (\core\log\sql_internal_reader in Moodle 2.7 and Moodle 2.8)&#039;&#039;&#039; - additionally has a method to return the table name which can be used to JOIN queries.&lt;br /&gt;
&lt;br /&gt;
The report decides which type of readers it can work with. Assuming we need a select reader, the following example will access available interfaces of this type.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$manager = get_log_manager();&lt;br /&gt;
// Remember to use &#039;\core\log\sql_select_reader&#039; instead of &#039;\core\log\sql_reader&#039; in Moodle 2.7 and Moodle 2.8.&lt;br /&gt;
$selectreaders = $manager-&amp;gt;get_readers(&#039;\core\log\sql_reader&#039;);&lt;br /&gt;
if ($selectreaders) {&lt;br /&gt;
    $reader = reset($selectreaders);&lt;br /&gt;
} else {&lt;br /&gt;
    // No available log reader found.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method \core\log\manager::get_readers() returns an associative array of singleton instances of enabled log store plugins implementing the reader interface. When a plugin finds the necessary log reader it can query the data from it. Refer to the interfaces for the list of methods they implement.&lt;br /&gt;
&lt;br /&gt;
For a transition period, a site may support both legacy logging and the new standard logging plugin. A report might need to access both log storages especially if it needs information that covers a long period of time that includes the transition from the legacy log to the new standard log. Please note that columns and event names are different in the new logging system and the legacy log, so separate queries will be needed.&lt;br /&gt;
&lt;br /&gt;
Here is an example of how to use the legacy log reader (which may be present but not enabled for writing).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$manager = get_log_manager();&lt;br /&gt;
$allreaders = $manager-&amp;gt;get_readers();&lt;br /&gt;
if (isset($allreaders[&#039;logstore_legacy&#039;])) {&lt;br /&gt;
    $legacyreader = $allreaders[&#039;logstore_legacy&#039;];&lt;br /&gt;
    if ($legacyreader-&amp;gt;is_logging()) {&lt;br /&gt;
        // All events continue to be recorded in {log} table.&lt;br /&gt;
    } else {&lt;br /&gt;
        // The {log} table is kept for storing the old logs only. New events are not written to it and must be taken from another log storage.&lt;br /&gt;
    }&lt;br /&gt;
} else {&lt;br /&gt;
    // You are probably developing for 2.10 and table {log} does not exist any more. Or administrator uninstalled the plugin.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Registering an observer ==&lt;br /&gt;
&lt;br /&gt;
Accessing logs on large Moodle instances will be slow and will cause load on the entire system. Some reports may wish to create their own mini log storages, storing only relevant events and perhaps only for a limited time. If you anticipate that such tables will be small, this can be an alternative solution to reading from logs.&lt;br /&gt;
&lt;br /&gt;
In order to implement an observer in a plugin you must:&lt;br /&gt;
* define a database table in PLUGINDIR/db/install.xml and create it in PLUGINDIR/db/upgrade.php;&lt;br /&gt;
* define event observers in PLUGINDIR/db/events.php with handler functions (see [[Event_2#Event_observers|Events 2]]);&lt;br /&gt;
* define a cron task that truncates the old entries from the table when they are no longer needed (define $plugin-&amp;gt;cron in your version.php);&lt;br /&gt;
* possibly create an upgrade script (in PLUGINDIR/db/upgrade.php) that migrates any relevant events from the legacy log table into the new observer table and&lt;br /&gt;
* re-write the SQL queries inside the plugin to access the new observer table instead of logs.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Writing PHPUnit tests#Logstores]]&lt;/div&gt;</summary>
		<author><name>Mackensen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Writing_PHPUnit_tests&amp;diff=50739</id>
		<title>Writing PHPUnit tests</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Writing_PHPUnit_tests&amp;diff=50739"/>
		<updated>2016-08-02T00:46:09Z</updated>

		<summary type="html">&lt;p&gt;Mackensen: /* Testing sending of emails */ add note on logstore tests&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.3}}&lt;br /&gt;
&lt;br /&gt;
Moodle PHPUnit integration is designed to allow easy adding of new tests. At the start of each test the state is automatically reset to fresh new installation (unless explicitly told not to reset).&lt;br /&gt;
&lt;br /&gt;
=Testcase classes=&lt;br /&gt;
&lt;br /&gt;
There are two basic test class that are supposed to used in all Moodle unit tests - basic_testcase and advanced_testcase. &#039;&#039;&#039;Please note it is strongly recommended to put only one testcase into each class file.&#039;&#039;&#039;&lt;br /&gt;
;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.&lt;br /&gt;
;advanced_testcase : Enhanced testcase class enhanced for easy testing of Moodle code.&lt;br /&gt;
&lt;br /&gt;
There is a third testcase class that is specially designed for testing of our Moodle database layer, it should not be used for other purposes.&lt;br /&gt;
&lt;br /&gt;
== Assertions ==&lt;br /&gt;
&lt;br /&gt;
The complete list of assertions can be found in the [http://www.phpunit.de/manual/3.7/en/appendixes.assertions.html phpunit manual].&lt;br /&gt;
==Sample plugin testcase==&lt;br /&gt;
&lt;br /&gt;
PHPUnit tests are located in &amp;lt;code&amp;gt;tests/*_test.php&amp;lt;/code&amp;gt; files in your plugin, for example mod/myplugin/tests/sample_test.php, the file should contain only one class that extends &amp;lt;code&amp;gt;advanced_testcase&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 class mod_myplugin_sample_testcase extends advanced_testcase {&lt;br /&gt;
     public function test_adding() {&lt;br /&gt;
         $this-&amp;gt;assertEquals(2, 1+2);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [[PHPUnit integration#Class and file naming rules]] for more information.&lt;br /&gt;
&lt;br /&gt;
==Inclusion of Moodle library files==&lt;br /&gt;
&lt;br /&gt;
If you want to include some Moodle library files you should always declare &#039;&#039;&#039;global $CFG&#039;&#039;&#039;. The reason is that testcase files may be included from non-moodle code which does not make the global $CFG available automatically.&lt;br /&gt;
&lt;br /&gt;
==Automatic state reset==&lt;br /&gt;
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-&amp;gt;resetAfterTest() to indicate that the database or changes of standard global variables are expected.&lt;br /&gt;
&lt;br /&gt;
If you received the error &amp;quot;Warning: unexpected database modification, resetting DB state&amp;quot; it is because the test is not using $this-&amp;gt;resetAfterTest().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 class mod_myplugin_testcase extends advanced_testcase {&lt;br /&gt;
     public function test_deleting() {&lt;br /&gt;
         global $DB;&lt;br /&gt;
         $this-&amp;gt;resetAfterTest(true);&lt;br /&gt;
         $DB-&amp;gt;delete_records(&#039;user&#039;);&lt;br /&gt;
         $this-&amp;gt;assertEmpty($DB-&amp;gt;get_records(&#039;user&#039;));&lt;br /&gt;
     }&lt;br /&gt;
     public function test_user_table_was_reset() {&lt;br /&gt;
         global $DB;&lt;br /&gt;
         $this-&amp;gt;assertEquals(2, $DB-&amp;gt;count_records(&#039;user&#039;, array()));&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Generators=&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==Creating users==&lt;br /&gt;
At the start of each test there are only two users present - guest and administrator. If you need to add more test accounts use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $user = $this-&amp;gt;getDataGenerator()-&amp;gt;create_user();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You may also specify properties of the user account, for example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $user1 = $this-&amp;gt;getDataGenerator()-&amp;gt;create_user(array(&#039;email&#039;=&amp;gt;&#039;user1@example.com&#039;, &#039;username&#039;=&amp;gt;&#039;user1&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default no user is logged-in, use setUser() method to change current $USER value:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $this-&amp;gt;setUser($user1);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Guest and admin accounts have a shortcut methods:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $this-&amp;gt;setGuestUser();&lt;br /&gt;
 $this-&amp;gt;setAdminUser();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Null can be used to set current user back to not-logged-in:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $this-&amp;gt;setUser(null);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating course categories==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $category1 = $this-&amp;gt;getDataGenerator()-&amp;gt;create_category();&lt;br /&gt;
 $category2 = $this-&amp;gt;getDataGenerator()-&amp;gt;create_category(array(&#039;name&#039;=&amp;gt;&#039;Some subcategory&#039;, &#039;parent&#039;=&amp;gt;$category1-&amp;gt;id));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating courses==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $course1 = $this-&amp;gt;getDataGenerator()-&amp;gt;create_course();&lt;br /&gt;
 &lt;br /&gt;
 $category = $this-&amp;gt;getDataGenerator()-&amp;gt;create_category();&lt;br /&gt;
 $course2 = $this-&amp;gt;getDataGenerator()-&amp;gt;create_course(array(&#039;name&#039;=&amp;gt;&#039;Some course&#039;, &#039;category&#039;=&amp;gt;$category-&amp;gt;id));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating activities==&lt;br /&gt;
&lt;br /&gt;
Some activity plugins include instance generators. The generator class are defined in plugindirectory/tests/generator/lib.php.&lt;br /&gt;
&lt;br /&gt;
Example of creation of new course with one page resource:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $course = $this-&amp;gt;getDataGenerator()-&amp;gt;create_course();&lt;br /&gt;
 $generator = $this-&amp;gt;getDataGenerator()-&amp;gt;get_plugin_generator(&#039;mod_page&#039;);&lt;br /&gt;
 $generator-&amp;gt;create_instance(array(&#039;course&#039;=&amp;gt;$course-&amp;gt;id));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating cohorts==&lt;br /&gt;
{{Moodle 2.4}}&lt;br /&gt;
Since 2.4 there the data generator supports creation of new cohorts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $cohort = $this-&amp;gt;getDataGenerator()-&amp;gt;create_cohort();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Simplified user enrolments==&lt;br /&gt;
{{Moodle 2.4}}&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;enrol_user($userid, $courseid);&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;enrol_user($userid, $courseid, $teacherroleid);&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;enrol_user($userid, $courseid, $teacherroleid, &#039;manual&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating scales==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_scale();&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_scale(array(&#039;name&#039; =&amp;gt; $name, &#039;scale&#039; =&amp;gt; $scale, &#039;courseid&#039; =&amp;gt; $courseid, &#039;userid&#039; =&amp;gt; $userid, &#039;description&#039; =&amp;gt; description, &#039;descriptionformat&#039; =&amp;gt; $descriptionformat));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating roles==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_role();&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_role(array(&#039;shortname&#039; =&amp;gt; $shortname, &#039;name&#039; =&amp;gt; $name, &#039;description&#039; =&amp;gt; description, &#039;archetype&#039; =&amp;gt; $archetype));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating tags==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_tag();&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_tag(array(&lt;br /&gt;
    &#039;userid&#039; =&amp;gt; $userid, &lt;br /&gt;
    &#039;rawname&#039; =&amp;gt; $rawname,&lt;br /&gt;
    &#039;name&#039; =&amp;gt; $name, &lt;br /&gt;
    &#039;tagtype&#039; =&amp;gt; $tagtype,&lt;br /&gt;
    &#039;description&#039; =&amp;gt; $description, &lt;br /&gt;
    &#039;descriptionformat&#039; =&amp;gt; $descriptionformat,&lt;br /&gt;
    &#039;flag&#039; =&amp;gt; $flag&lt;br /&gt;
));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Groups==&lt;br /&gt;
&lt;br /&gt;
===Creating groups===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_group(array(&#039;courseid&#039; =&amp;gt; $courseid));&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_group(array(&#039;courseid&#039; =&amp;gt; $courseid, &#039;name&#039; =&amp;gt; $name, &#039;description&#039; =&amp;gt; $description, &#039;descriptionformat&#039; =&amp;gt; $descriptionformat));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding users to groups===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_group_member(array(&#039;userid&#039; =&amp;gt; $userid, &#039;groupid&#039; =&amp;gt; $groupid));&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_group_member(array(&#039;userid&#039; =&amp;gt; $userid, &#039;groupid&#039; =&amp;gt; $groupid, &#039;component&#039; =&amp;gt; $component, &#039;itemid&#039; =&amp;gt; $itemid));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating groupings===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_grouping(array(&#039;courseid&#039; =&amp;gt; $courseid));&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_grouping(array(&#039;courseid&#039; =&amp;gt; $courseid, &#039;name&#039; =&amp;gt; $name, &#039;description&#039; =&amp;gt; $description, &#039;descriptionformat&#039; =&amp;gt; $descriptionformat));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding groups to groupings===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_grouping_group(array(&#039;groupingid&#039; =&amp;gt; $groupingid, &#039;groupid&#039; =&amp;gt; $groupid));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Repositories==&lt;br /&gt;
&lt;br /&gt;
===Creating repository instances===&lt;br /&gt;
{{Moodle 2.5}}&lt;br /&gt;
Some respository plugins include instance generators. The generator class are defined in plugindirectory/tests/generator/lib.php..&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_repository($type, $record, $options);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating repository types===&lt;br /&gt;
{{Moodle 2.5}}&lt;br /&gt;
Some respository plugins include type generators. The generator class are defined in plugindirectory/tests/generator/lib.php..&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_repository_type($type, $record, $options);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating grades==&lt;br /&gt;
&lt;br /&gt;
===Grade categories===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_grade_category(array(&#039;courseid&#039; =&amp;gt; $courseid));&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_grade_category(array(&#039;courseid&#039; =&amp;gt; $courseid, &#039;fullname&#039; =&amp;gt; $fullname));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Grade items===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_grade_item();&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_grade_item(array(&#039;itemtype&#039; =&amp;gt; $itemtype, &#039;itemname&#039; =&amp;gt; $itemname, &#039;outcomeid&#039; =&amp;gt; $outcomeid, &#039;scaleid&#039; =&amp;gt; $scaleid, &#039;gradetype&#039; =&amp;gt; $gradetype));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Outcomes===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_grade_outcome();&lt;br /&gt;
$this-&amp;gt;getDataGenerator()-&amp;gt;create_grade_item(array(&#039;fullname&#039; =&amp;gt; $fullname));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Other types of plugin==&lt;br /&gt;
{{Moodle 2.5}}&lt;br /&gt;
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-&amp;gt;getDataGenerator()-&amp;gt;get_plugin_generator($frankenstylecomponentname);&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=Long tests=&lt;br /&gt;
&lt;br /&gt;
All standard test should execute as fast as possible. Tests that take a loner time to execute (&amp;gt;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.&lt;br /&gt;
&lt;br /&gt;
=Large test data=&lt;br /&gt;
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]]&lt;br /&gt;
&lt;br /&gt;
=Testing sending of messages=&lt;br /&gt;
{{Moodle 2.4}}&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;preventResetByRollback();&lt;br /&gt;
$sink = $this-&amp;gt;redirectMessages();&lt;br /&gt;
//... code that is sending messages&lt;br /&gt;
$messages = $sink-&amp;gt;get_messages();&lt;br /&gt;
$this-&amp;gt;assertEquals(3, count($messages));&lt;br /&gt;
//.. test messages were generated in correct order with appropriate content&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Testing sending of emails=&lt;br /&gt;
{{Moodle 2.6}}&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
To test code using messaging first unset &#039;noemailever&#039; setting and then redirect the emails into a new message sink where you can inspect the results later.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
unset_config(&#039;noemailever&#039;);&lt;br /&gt;
$sink = $this-&amp;gt;redirectEmails();&lt;br /&gt;
//... code that is sending email&lt;br /&gt;
$messages = $sink-&amp;gt;get_messages();&lt;br /&gt;
$this-&amp;gt;assertEquals(1, count($messages));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Logstores=&lt;br /&gt;
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.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;preventResetByRollback();&lt;br /&gt;
set_config(&#039;enabled_stores&#039;, &#039;logstore_standard&#039;, &#039;tool_log&#039;);&lt;br /&gt;
set_config(&#039;buffersize&#039;, 0, &#039;logstore_standard&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Extra test settings=&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
There are several ways how to inject your custom settings:&lt;br /&gt;
* define test setting constants in your phpunit.xml file&lt;br /&gt;
* define test setting constants in your config.php&lt;br /&gt;
&lt;br /&gt;
These constants may be then used in your test or plugin code.&lt;br /&gt;
&lt;br /&gt;
=See also=&lt;br /&gt;
* [[PHPUnit integration]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Unit testing]]&lt;/div&gt;</summary>
		<author><name>Mackensen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=PHPUnit&amp;diff=50482</id>
		<title>PHPUnit</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=PHPUnit&amp;diff=50482"/>
		<updated>2016-06-30T01:38:22Z</updated>

		<summary type="html">&lt;p&gt;Mackensen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.3}}&lt;br /&gt;
&lt;br /&gt;
=What is PHPUnit=&lt;br /&gt;
PHPUnit by Sebastian Bergmann is an advanced unit testing framework for PHP. It is installed as Composer dependency and is not part of Moodle installation. To run PHPUnit tests, you have to manually install it on your development computer or test server.&lt;br /&gt;
&lt;br /&gt;
Read the excellent guide at&lt;br /&gt;
* [http://phpunit.de/manual/current/en/index.html PHPUnit Manual]&lt;br /&gt;
&lt;br /&gt;
=Installation of PHPUnit via Composer=&lt;br /&gt;
&lt;br /&gt;
Windows may require additional installation steps.&lt;br /&gt;
On Windows go to https://getcomposer.org/download/ and download the Composer-Setup.exe file&lt;br /&gt;
&lt;br /&gt;
* Execute Composer installer&lt;br /&gt;
&lt;br /&gt;
 cd /your/moodle/dirroot&lt;br /&gt;
 php composer.phar install&lt;br /&gt;
&lt;br /&gt;
(If that gives you connection problems try...)&lt;br /&gt;
&lt;br /&gt;
 php composer.phar install --prefer-source&lt;br /&gt;
&lt;br /&gt;
Troubleshooting:&lt;br /&gt;
* On Windows if you are behind a proxy you will need to setup an environment variable called HTTP_PROXY with a value detailing your HTTP Proxy address and port before composer will correctly download files.&lt;br /&gt;
* You may be prompted for github credentials when installing composer dependencies.&lt;br /&gt;
** This is used to generate an personal access token to avoid being rate limited by github.&lt;br /&gt;
** If you have Two Factor Authentication enabled on your github account, or do not wish to supply your own credentials you will need to generate a token manually:&lt;br /&gt;
*** Visit https://github.com/settings/applications and request personal access token&lt;br /&gt;
*** Copy this token and add it to your [https://gist.github.com/andrewnicols/c5377ed25a9df1006ce1 ~/.composer/config.json]&lt;br /&gt;
** ( See [https://github.com/composer/composer/issues/2280 composer issue #2280] for further details of this bug.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Detailed instructions:&lt;br /&gt;
* [http://getcomposer.org/doc/00-intro.md Composer documentation]&lt;br /&gt;
&lt;br /&gt;
Detailed instructions:&lt;br /&gt;
* [[PHPUnit installation in Windows]]&lt;br /&gt;
* [[PHPUnit installation in OS X]]&lt;br /&gt;
&lt;br /&gt;
== Uninstalling previous PEAR based version ==&lt;br /&gt;
&lt;br /&gt;
Before using composer, this page used to suggest to install phpunit via PEAR. If you did so, you may wish to uninstall that package now. This should work:&lt;br /&gt;
&lt;br /&gt;
   $ pear uninstall phpunit/DbUnit&lt;br /&gt;
   $ pear uninstall phpunit/PHPUnit&lt;br /&gt;
&lt;br /&gt;
=Initialisation of test environment=&lt;br /&gt;
&lt;br /&gt;
Our PHPUnit integration requires a dedicated database and dataroot.  First, add a new dataroot directory and prefix into your config.php, you can find examples in config-dist.php (scroll down to &#039;Section 9&#039;).&lt;br /&gt;
&lt;br /&gt;
 $CFG-&amp;gt;phpunit_prefix = &#039;phpu_&#039;;&lt;br /&gt;
 $CFG-&amp;gt;phpunit_dataroot = &#039;/home/example/phpu_moodledata&#039;;&lt;br /&gt;
&lt;br /&gt;
If your system does not have a direct connection to the Internet, you also need to specify your proxy in config.php - even though you normally specify it by using the admin settings user interface. (If you do not use a proxy, you can skip this step.) Check the settings on the relevant admin settings page, or from the mdl_config table in your database, if you are unsure of the correct values.&lt;br /&gt;
 &lt;br /&gt;
 // Normal proxy settings&lt;br /&gt;
 $CFG-&amp;gt;proxyhost = &#039;wwwcache.example.org&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxyport = 80;&lt;br /&gt;
 $CFG-&amp;gt;proxytype = &#039;HTTP&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxybypass = &#039;localhost, 127.0.0.1, .example.org&#039;;&lt;br /&gt;
 // Omit the next lines if your proxy doesn&#039;t need a username/password:&lt;br /&gt;
 $CFG-&amp;gt;proxyuser = &#039;systemusername&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxypassword = &#039;systempassword&#039;;&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.8.5 onwards, you can also provide specific database settings for unit testing (if these are not provided, the standard database settings will be used):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;$CFG-&amp;gt;phpunit_dbtype    = &#039;pgsql&#039;;      // &#039;pgsql&#039;, &#039;mariadb&#039;, &#039;mysqli&#039;, &#039;mssql&#039;, &#039;sqlsrv&#039; or &#039;oci&#039;&lt;br /&gt;
$CFG-&amp;gt;phpunit_dblibrary = &#039;native&#039;;     // &#039;native&#039; only at the moment&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbhost    = &#039;127.0.0.1&#039;;  // eg &#039;localhost&#039; or &#039;db.isp.com&#039; or IP&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbname    = &#039;mytestdb&#039;;     // database name, eg moodle&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbuser    = &#039;postgres&#039;;   // your database username&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbpass    = &#039;some_password&#039;;   // your database password&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you need to initialise the test environment using following command.&lt;br /&gt;
&lt;br /&gt;
 cd /home/example/moodle&lt;br /&gt;
 php admin/tool/phpunit/cli/init.php&lt;br /&gt;
&lt;br /&gt;
This command has to be repeated after any upgrade, plugin (un)installation or if you have added tests to a plugin you are developing:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; make sure that your php cli executable (or the one you want to use) is correctly on your path as the individual init scripts will call it repeatedly. Also, ensure en_AU locale is installed on your server.&lt;br /&gt;
&lt;br /&gt;
== LDAP ==&lt;br /&gt;
If you want to run LDAP unit tests you must have a working, configured LDAP environment on your test server. There must be a basic LDAP tree structure in place or tests will fail with &amp;quot;Search: No such object&amp;quot;. Build an LDAP tree structure in a new shell prompt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ ldapadd -H ldap://127.0.0.1 -D &amp;quot;cn=admin,dc=yourcomputer,dc=local&amp;quot; -W&lt;br /&gt;
dn:dc=yourcomputer,dc=local&lt;br /&gt;
objectClass:dcObject&lt;br /&gt;
objectClass:organizationalUnit&lt;br /&gt;
dc:yourcomputer&lt;br /&gt;
ou:YOURCOMPUTER&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In config.php tell Moodle where to look for your test LDAP environment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_HOST_URL&#039;, &#039;ldap://127.0.0.1&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_BIND_DN&#039;, &#039;cn=admin,dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_BIND_PW&#039;, &#039;*&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_DOMAIN&#039;, &#039;dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Test execution=&lt;br /&gt;
&lt;br /&gt;
To execute all test suites from main configuration file execute the &amp;lt;code&amp;gt;vendor/bin/phpunit&amp;lt;/code&amp;gt; script from your &amp;lt;code&amp;gt;$CFG-&amp;gt;dirroot&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
&lt;br /&gt;
 cd /home/example/moodle&lt;br /&gt;
 vendor/bin/phpunit&lt;br /&gt;
&lt;br /&gt;
The rest of examples uses &amp;lt;code&amp;gt;phpunit&amp;lt;/code&amp;gt;, please substitute it with &amp;lt;code&amp;gt;vendor/bin/phpunit&amp;lt;/code&amp;gt; or create a shortcut in your dirroot.&lt;br /&gt;
&lt;br /&gt;
In IDEs, you may need to specify the path to the PHPUnit configuration file. Use the absolute path to &amp;lt;code&amp;gt;phpunit.xml&amp;lt;/code&amp;gt; from your &amp;lt;code&amp;gt;$CFG-&amp;gt;dirroot&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There is an alternative script for running of tests via web interface: &amp;lt;code&amp;gt;admin/tool/phpunit/webrunner.php&amp;lt;/code&amp;gt;. Use this as the last resort only when you cannot use the command-line interface on your test server. It will most probably break due to permissions problems if you try to execute it both from command-line and from webrunner. This feature is not officially supported.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===How to run only some tests===&lt;br /&gt;
&lt;br /&gt;
==== Running a single test quickly ====&lt;br /&gt;
&lt;br /&gt;
The fastest way to run a single test is:&lt;br /&gt;
&lt;br /&gt;
 vendor/bin/phpunit my_test_class_name my/tests/filename.php&lt;br /&gt;
&lt;br /&gt;
This is faster than other methods because it avoids the need to search for the test file, but you should be careful because it may be possible to run tests this way which are not included in the normal run. If you use this method, do at least one full test run (or --group run, as below) to ensure the test can be found.&lt;br /&gt;
&lt;br /&gt;
Please note the path name is optional if the testcase class and file names are standardised as described in [[Writing PHPUnit tests]].&lt;br /&gt;
&lt;br /&gt;
==== Using the @group annotation ====&lt;br /&gt;
&lt;br /&gt;
If you add annotations like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Unit tests for {@link stack_cas_keyval}.&lt;br /&gt;
 * @group qtype_stack&lt;br /&gt;
 */&lt;br /&gt;
class qtype_stack_cas_keyval_exception_testcase extends basic_testcase {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to all the classes in your plugin, then you can run just the tests for your plugin by doing&lt;br /&gt;
&lt;br /&gt;
 phpunit --group qtype_stack&lt;br /&gt;
&lt;br /&gt;
Therefore, it is suggested that you annotate all your tests with the Frankenstyle name of your plugin.&lt;br /&gt;
&lt;br /&gt;
==== Using multiple phpunit.xml files ====&lt;br /&gt;
&lt;br /&gt;
It&#039;s easy to create alternative phpunit.xml files defining which tests must be run together. For reference, take a look to the default /phpunit.xml available in your base directory once the testing environment has been initialised. After creating the custom file you will be able to run those tests with&lt;br /&gt;
&lt;br /&gt;
 vendor/bin/phpunit -c path/to/your/alternative/phpunit/file.xml&lt;br /&gt;
&lt;br /&gt;
Also, for commodity, you can use this command:&lt;br /&gt;
&lt;br /&gt;
 php admin/tool/phpunit/cli/util.php --buildcomponentconfigs&lt;br /&gt;
&lt;br /&gt;
It will, automatically, create one valid phpunit.xml file within each component (plugin or subsystem) and other important directories, so later you will be able to execute tests like&lt;br /&gt;
&lt;br /&gt;
 vendor/bin/phpunit -c mod/forum[/phpunit.xml]  // Note that it&#039;s not needed to specify the name of the file (if it is &#039;phpunit.xml&#039;).&lt;br /&gt;
 vendor/bin/phpunit -c question&lt;br /&gt;
 vendor/bin/phpunit -c question/type/calculated&lt;br /&gt;
 vendor/bin/phpunit -c backup&lt;br /&gt;
 vendor/bin/phpunit -c lib/dml&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
or, also&lt;br /&gt;
&lt;br /&gt;
 cd directory/with/phpunit.xml&lt;br /&gt;
 phpunit&lt;br /&gt;
&lt;br /&gt;
=External test resources=&lt;br /&gt;
{{Moodle 2.6}}&lt;br /&gt;
By default Moodle phpunit tests contact http://download.moodle.org server when testing curl related functionality. Optionally you may checkout a local copy of the test scripts and access it instead:&lt;br /&gt;
&lt;br /&gt;
# clone https://github.com/moodlehq/moodle-exttests to web directory&lt;br /&gt;
# add to your config.php or modify phpunit.xml file &amp;lt;code php&amp;gt;define(&#039;TEST_EXTERNAL_FILES_HTTP_URL&#039;, &#039;http://localhost/moodle-exttests&#039;);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing new tests=&lt;br /&gt;
* read [http://www.phpunit.de/manual/current/en/ official PHPUnit online documentation]&lt;br /&gt;
* see [[Writing PHPUnit tests]]&lt;br /&gt;
&lt;br /&gt;
=Conversion of existing SimpleTests=&lt;br /&gt;
* see [[SimpleTest conversion]]&lt;br /&gt;
&lt;br /&gt;
=PHPUnit support in IDEs=&lt;br /&gt;
&lt;br /&gt;
* [[Setting up Eclipse]]&lt;br /&gt;
* [[Setting up Netbeans]]&lt;br /&gt;
* [[Setting up PhpStorm]]&lt;br /&gt;
&lt;br /&gt;
=Common Unit Test Problems=&lt;br /&gt;
[[Common unit test problems]]&lt;br /&gt;
&lt;br /&gt;
=Performance=&lt;br /&gt;
&lt;br /&gt;
A typical run of full PHPUnit tests for Moodle 2.7 takes 10-20 minutes depending on the machine. If tests run slowly for you:&lt;br /&gt;
&lt;br /&gt;
* Ensure you are using a database and filesystem running on the same machine that is running the tests (not on a remote server).&lt;br /&gt;
* Apply developer-only performance settings to your database: [[Postgres Tuning For Developers]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Unit testing]]&lt;/div&gt;</summary>
		<author><name>Mackensen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=PHPUnit&amp;diff=50481</id>
		<title>PHPUnit</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=PHPUnit&amp;diff=50481"/>
		<updated>2016-06-30T01:37:48Z</updated>

		<summary type="html">&lt;p&gt;Mackensen: /* Initialisation of test environment */ how to bootstrap the LDAP environment&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.3}}&lt;br /&gt;
&lt;br /&gt;
=What is PHPUnit=&lt;br /&gt;
PHPUnit by Sebastian Bergmann is an advanced unit testing framework for PHP. It is installed as Composer dependency and is not part of Moodle installation. To run PHPUnit tests, you have to manually install it on your development computer or test server.&lt;br /&gt;
&lt;br /&gt;
Read the excellent guide at&lt;br /&gt;
* [http://phpunit.de/manual/current/en/index.html PHPUnit Manual]&lt;br /&gt;
&lt;br /&gt;
=Installation of PHPUnit via Composer=&lt;br /&gt;
&lt;br /&gt;
Windows may require additional installation steps.&lt;br /&gt;
On Windows go to https://getcomposer.org/download/ and download the Composer-Setup.exe file&lt;br /&gt;
&lt;br /&gt;
* Execute Composer installer&lt;br /&gt;
&lt;br /&gt;
 cd /your/moodle/dirroot&lt;br /&gt;
 php composer.phar install&lt;br /&gt;
&lt;br /&gt;
(If that gives you connection problems try...)&lt;br /&gt;
&lt;br /&gt;
 php composer.phar install --prefer-source&lt;br /&gt;
&lt;br /&gt;
Troubleshooting:&lt;br /&gt;
* On Windows if you are behind a proxy you will need to setup an environment variable called HTTP_PROXY with a value detailing your HTTP Proxy address and port before composer will correctly download files.&lt;br /&gt;
* You may be prompted for github credentials when installing composer dependencies.&lt;br /&gt;
** This is used to generate an personal access token to avoid being rate limited by github.&lt;br /&gt;
** If you have Two Factor Authentication enabled on your github account, or do not wish to supply your own credentials you will need to generate a token manually:&lt;br /&gt;
*** Visit https://github.com/settings/applications and request personal access token&lt;br /&gt;
*** Copy this token and add it to your [https://gist.github.com/andrewnicols/c5377ed25a9df1006ce1 ~/.composer/config.json]&lt;br /&gt;
** ( See [https://github.com/composer/composer/issues/2280 composer issue #2280] for further details of this bug.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Detailed instructions:&lt;br /&gt;
* [http://getcomposer.org/doc/00-intro.md Composer documentation]&lt;br /&gt;
&lt;br /&gt;
Detailed instructions:&lt;br /&gt;
* [[PHPUnit installation in Windows]]&lt;br /&gt;
* [[PHPUnit installation in OS X]]&lt;br /&gt;
&lt;br /&gt;
== Uninstalling previous PEAR based version ==&lt;br /&gt;
&lt;br /&gt;
Before using composer, this page used to suggest to install phpunit via PEAR. If you did so, you may wish to uninstall that package now. This should work:&lt;br /&gt;
&lt;br /&gt;
   $ pear uninstall phpunit/DbUnit&lt;br /&gt;
   $ pear uninstall phpunit/PHPUnit&lt;br /&gt;
&lt;br /&gt;
=Initialisation of test environment=&lt;br /&gt;
&lt;br /&gt;
Our PHPUnit integration requires a dedicated database and dataroot.  First, add a new dataroot directory and prefix into your config.php, you can find examples in config-dist.php (scroll down to &#039;Section 9&#039;).&lt;br /&gt;
&lt;br /&gt;
 $CFG-&amp;gt;phpunit_prefix = &#039;phpu_&#039;;&lt;br /&gt;
 $CFG-&amp;gt;phpunit_dataroot = &#039;/home/example/phpu_moodledata&#039;;&lt;br /&gt;
&lt;br /&gt;
If your system does not have a direct connection to the Internet, you also need to specify your proxy in config.php - even though you normally specify it by using the admin settings user interface. (If you do not use a proxy, you can skip this step.) Check the settings on the relevant admin settings page, or from the mdl_config table in your database, if you are unsure of the correct values.&lt;br /&gt;
 &lt;br /&gt;
 // Normal proxy settings&lt;br /&gt;
 $CFG-&amp;gt;proxyhost = &#039;wwwcache.example.org&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxyport = 80;&lt;br /&gt;
 $CFG-&amp;gt;proxytype = &#039;HTTP&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxybypass = &#039;localhost, 127.0.0.1, .example.org&#039;;&lt;br /&gt;
 // Omit the next lines if your proxy doesn&#039;t need a username/password:&lt;br /&gt;
 $CFG-&amp;gt;proxyuser = &#039;systemusername&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxypassword = &#039;systempassword&#039;;&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.8.5 onwards, you can also provide specific database settings for unit testing (if these are not provided, the standard database settings will be used):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;$CFG-&amp;gt;phpunit_dbtype    = &#039;pgsql&#039;;      // &#039;pgsql&#039;, &#039;mariadb&#039;, &#039;mysqli&#039;, &#039;mssql&#039;, &#039;sqlsrv&#039; or &#039;oci&#039;&lt;br /&gt;
$CFG-&amp;gt;phpunit_dblibrary = &#039;native&#039;;     // &#039;native&#039; only at the moment&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbhost    = &#039;127.0.0.1&#039;;  // eg &#039;localhost&#039; or &#039;db.isp.com&#039; or IP&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbname    = &#039;mytestdb&#039;;     // database name, eg moodle&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbuser    = &#039;postgres&#039;;   // your database username&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbpass    = &#039;some_password&#039;;   // your database password&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you need to initialise the test environment using following command.&lt;br /&gt;
&lt;br /&gt;
 cd /home/example/moodle&lt;br /&gt;
 php admin/tool/phpunit/cli/init.php&lt;br /&gt;
&lt;br /&gt;
This command has to be repeated after any upgrade, plugin (un)installation or if you have added tests to a plugin you are developing:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; make sure that your php cli executable (or the one you want to use) is correctly on your path as the individual init scripts will call it repeatedly. Also, ensure en_AU locale is installed on your server.&lt;br /&gt;
&lt;br /&gt;
== LDAP ==&lt;br /&gt;
If you want to run LDAP unit tests you must have a working, configured LDAP environment on your test server. There must be a basic LDAP tree structure in place or tests will fail with &amp;quot;Search: No such object&amp;quot;. Build an LDAP tree structure in a new shell prompt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ ldapadd -H ldap://127.0.0.1 -D &amp;quot;cn=admin,dc=yourcomputer,dc=local&amp;quot; -W&lt;br /&gt;
dn:dc=yourcomputer,dc=local&lt;br /&gt;
objectClass:dcObject&lt;br /&gt;
objectClass:organizationalUnit&lt;br /&gt;
dc:yourcomputer&lt;br /&gt;
ou:YOURCOMPUTER&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In config.php tell Moodle where to look for your test LDAP environment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_HOST_URL&#039;, &#039;ldap://127.0.0.1&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_BIND_DN&#039;, &#039;cn=admin,dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_BIND_PW&#039;, &#039;*&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_DOMAIN&#039;, &#039;dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
&lt;br /&gt;
=Test execution=&lt;br /&gt;
&lt;br /&gt;
To execute all test suites from main configuration file execute the &amp;lt;code&amp;gt;vendor/bin/phpunit&amp;lt;/code&amp;gt; script from your &amp;lt;code&amp;gt;$CFG-&amp;gt;dirroot&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
&lt;br /&gt;
 cd /home/example/moodle&lt;br /&gt;
 vendor/bin/phpunit&lt;br /&gt;
&lt;br /&gt;
The rest of examples uses &amp;lt;code&amp;gt;phpunit&amp;lt;/code&amp;gt;, please substitute it with &amp;lt;code&amp;gt;vendor/bin/phpunit&amp;lt;/code&amp;gt; or create a shortcut in your dirroot.&lt;br /&gt;
&lt;br /&gt;
In IDEs, you may need to specify the path to the PHPUnit configuration file. Use the absolute path to &amp;lt;code&amp;gt;phpunit.xml&amp;lt;/code&amp;gt; from your &amp;lt;code&amp;gt;$CFG-&amp;gt;dirroot&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There is an alternative script for running of tests via web interface: &amp;lt;code&amp;gt;admin/tool/phpunit/webrunner.php&amp;lt;/code&amp;gt;. Use this as the last resort only when you cannot use the command-line interface on your test server. It will most probably break due to permissions problems if you try to execute it both from command-line and from webrunner. This feature is not officially supported.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===How to run only some tests===&lt;br /&gt;
&lt;br /&gt;
==== Running a single test quickly ====&lt;br /&gt;
&lt;br /&gt;
The fastest way to run a single test is:&lt;br /&gt;
&lt;br /&gt;
 vendor/bin/phpunit my_test_class_name my/tests/filename.php&lt;br /&gt;
&lt;br /&gt;
This is faster than other methods because it avoids the need to search for the test file, but you should be careful because it may be possible to run tests this way which are not included in the normal run. If you use this method, do at least one full test run (or --group run, as below) to ensure the test can be found.&lt;br /&gt;
&lt;br /&gt;
Please note the path name is optional if the testcase class and file names are standardised as described in [[Writing PHPUnit tests]].&lt;br /&gt;
&lt;br /&gt;
==== Using the @group annotation ====&lt;br /&gt;
&lt;br /&gt;
If you add annotations like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Unit tests for {@link stack_cas_keyval}.&lt;br /&gt;
 * @group qtype_stack&lt;br /&gt;
 */&lt;br /&gt;
class qtype_stack_cas_keyval_exception_testcase extends basic_testcase {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to all the classes in your plugin, then you can run just the tests for your plugin by doing&lt;br /&gt;
&lt;br /&gt;
 phpunit --group qtype_stack&lt;br /&gt;
&lt;br /&gt;
Therefore, it is suggested that you annotate all your tests with the Frankenstyle name of your plugin.&lt;br /&gt;
&lt;br /&gt;
==== Using multiple phpunit.xml files ====&lt;br /&gt;
&lt;br /&gt;
It&#039;s easy to create alternative phpunit.xml files defining which tests must be run together. For reference, take a look to the default /phpunit.xml available in your base directory once the testing environment has been initialised. After creating the custom file you will be able to run those tests with&lt;br /&gt;
&lt;br /&gt;
 vendor/bin/phpunit -c path/to/your/alternative/phpunit/file.xml&lt;br /&gt;
&lt;br /&gt;
Also, for commodity, you can use this command:&lt;br /&gt;
&lt;br /&gt;
 php admin/tool/phpunit/cli/util.php --buildcomponentconfigs&lt;br /&gt;
&lt;br /&gt;
It will, automatically, create one valid phpunit.xml file within each component (plugin or subsystem) and other important directories, so later you will be able to execute tests like&lt;br /&gt;
&lt;br /&gt;
 vendor/bin/phpunit -c mod/forum[/phpunit.xml]  // Note that it&#039;s not needed to specify the name of the file (if it is &#039;phpunit.xml&#039;).&lt;br /&gt;
 vendor/bin/phpunit -c question&lt;br /&gt;
 vendor/bin/phpunit -c question/type/calculated&lt;br /&gt;
 vendor/bin/phpunit -c backup&lt;br /&gt;
 vendor/bin/phpunit -c lib/dml&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
or, also&lt;br /&gt;
&lt;br /&gt;
 cd directory/with/phpunit.xml&lt;br /&gt;
 phpunit&lt;br /&gt;
&lt;br /&gt;
=External test resources=&lt;br /&gt;
{{Moodle 2.6}}&lt;br /&gt;
By default Moodle phpunit tests contact http://download.moodle.org server when testing curl related functionality. Optionally you may checkout a local copy of the test scripts and access it instead:&lt;br /&gt;
&lt;br /&gt;
# clone https://github.com/moodlehq/moodle-exttests to web directory&lt;br /&gt;
# add to your config.php or modify phpunit.xml file &amp;lt;code php&amp;gt;define(&#039;TEST_EXTERNAL_FILES_HTTP_URL&#039;, &#039;http://localhost/moodle-exttests&#039;);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing new tests=&lt;br /&gt;
* read [http://www.phpunit.de/manual/current/en/ official PHPUnit online documentation]&lt;br /&gt;
* see [[Writing PHPUnit tests]]&lt;br /&gt;
&lt;br /&gt;
=Conversion of existing SimpleTests=&lt;br /&gt;
* see [[SimpleTest conversion]]&lt;br /&gt;
&lt;br /&gt;
=PHPUnit support in IDEs=&lt;br /&gt;
&lt;br /&gt;
* [[Setting up Eclipse]]&lt;br /&gt;
* [[Setting up Netbeans]]&lt;br /&gt;
* [[Setting up PhpStorm]]&lt;br /&gt;
&lt;br /&gt;
=Common Unit Test Problems=&lt;br /&gt;
[[Common unit test problems]]&lt;br /&gt;
&lt;br /&gt;
=Performance=&lt;br /&gt;
&lt;br /&gt;
A typical run of full PHPUnit tests for Moodle 2.7 takes 10-20 minutes depending on the machine. If tests run slowly for you:&lt;br /&gt;
&lt;br /&gt;
* Ensure you are using a database and filesystem running on the same machine that is running the tests (not on a remote server).&lt;br /&gt;
* Apply developer-only performance settings to your database: [[Postgres Tuning For Developers]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Unit testing]]&lt;/div&gt;</summary>
		<author><name>Mackensen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing&amp;diff=48137</id>
		<title>Acceptance testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing&amp;diff=48137"/>
		<updated>2015-06-27T21:31:13Z</updated>

		<summary type="html">&lt;p&gt;Mackensen: /* See also */ +Vagrant&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This page describes how we describe Moodle&#039;s functionalities and automatically test them.&lt;br /&gt;
&lt;br /&gt;
Behat is a behavioural driven development (BDD) tool written in PHP, it can parse a human-readable list of sentences (called steps) and execute actions in a browser using Selenium or other tools to simulate user interactions.&lt;br /&gt;
&lt;br /&gt;
For technical info: [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
Behat parses and executes features files which describe Moodle&#039;s features (for example &#039;&#039;Post in a forum&#039;&#039;). Each feature file is composed of many scenarios (for example &#039;&#039;Add a post to a discussion&#039;&#039; or &#039;&#039;Create a new discussion&#039;&#039;), and finally each scenario is composed of steps (for example  &#039;&#039;I press &amp;quot;Post to forum&amp;quot;&#039;&#039; or &#039;&#039;I should see &amp;quot;My post title&amp;quot;&#039;&#039;). When the feature file is executed, every step internally is translated into a PHP method and is executed.&lt;br /&gt;
&lt;br /&gt;
These features are executed nightly on the HQ servers using all the supported databases (MySQL, PostgreSQL, MSSQL and Oracle) and with different browsers (Firefox, Internet Explorer, Safari and Chrome) to avoid regressions and to test new functionalities.&lt;br /&gt;
&lt;br /&gt;
=== Examples ===&lt;br /&gt;
&lt;br /&gt;
Note that these snippets are only examples and may not work.&lt;br /&gt;
&lt;br /&gt;
* There is a closed list of steps to use in the features, a feature written with the basic (or low-level) steps looks like this:&lt;br /&gt;
  @auth&lt;br /&gt;
  &#039;&#039;&#039;Feature&#039;&#039;&#039;: Login&lt;br /&gt;
    In order to login&lt;br /&gt;
    As a moodle user&lt;br /&gt;
    I need to be able to validate the username and password against moodle&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;Scenario&#039;&#039;&#039;: Login as an existing user&lt;br /&gt;
      Given I am on &amp;quot;login/index.php&amp;quot;&lt;br /&gt;
      When I fill in &amp;quot;username&amp;quot; with &amp;quot;admin&amp;quot;&lt;br /&gt;
      And I fill in &amp;quot;password&amp;quot; with &amp;quot;moodle&amp;quot;&lt;br /&gt;
      And I press &amp;quot;loginbtn&amp;quot;&lt;br /&gt;
      Then I should see &amp;quot;Moodle 101: Course Name&amp;quot;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;Scenario&#039;&#039;&#039;: Login as an unexisting user&lt;br /&gt;
      Given I am on &amp;quot;login/index.php&amp;quot;&lt;br /&gt;
      When I fill in &amp;quot;username&amp;quot; with &amp;quot;admin&amp;quot;&lt;br /&gt;
      And I fill in &amp;quot;password&amp;quot; with &amp;quot;moodle&amp;quot;&lt;br /&gt;
      And I press &amp;quot;loginbtn&amp;quot;&lt;br /&gt;
      Then I should see &amp;quot;Moodle 101: Course Name&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Note that The 3 sentences below &#039;&#039;Feature: Login&#039;&#039; are only information about what we want to test.&lt;br /&gt;
&lt;br /&gt;
These are simple scenarios, but most of Moodle&#039;s functionalities would require a huge list of this steps to test a scenario, imagine a &#039;&#039;Add a post to a discussion&#039;&#039; scenario; you need to login, create a course, create a user and enrol it in the course... Most of this steps is not what we intend to test in a &#039;&#039;Post in a forum&#039;&#039; feature, Moodle provides extra steps to quickly set up the context required to test a Moodle feature, for example:&lt;br /&gt;
&lt;br /&gt;
  @mod @mod_forum&lt;br /&gt;
  &#039;&#039;&#039;Feature&#039;&#039;&#039;: Add forum activities and discussions&lt;br /&gt;
    In order to discuss topics with other users&lt;br /&gt;
    As a moodle teacher&lt;br /&gt;
    I need to add forum activities to moodle courses&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;Scenario&#039;&#039;&#039;: Add a forum and a discussion&lt;br /&gt;
      &#039;&#039;&#039;Given&#039;&#039;&#039; the following &amp;quot;users&amp;quot; exists:&lt;br /&gt;
        | username | firstname | lastname | email |&lt;br /&gt;
        | teacher1 | Teacher | 1 | teacher1@asd.com |&lt;br /&gt;
      &#039;&#039;&#039;And&#039;&#039;&#039; the following &amp;quot;courses&amp;quot; exists:&lt;br /&gt;
        | fullname | shortname | category |&lt;br /&gt;
        | Course 1 | C1 | 0 |&lt;br /&gt;
      &#039;&#039;&#039;And&#039;&#039;&#039; the following &amp;quot;course enrolments&amp;quot; exists:&lt;br /&gt;
        | user | course | role |&lt;br /&gt;
        | teacher1 | C1 | editingteacher |&lt;br /&gt;
      &#039;&#039;&#039;And&#039;&#039;&#039; I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
      &#039;&#039;&#039;And&#039;&#039;&#039; I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
      &#039;&#039;&#039;And&#039;&#039;&#039; I turn editing mode on&lt;br /&gt;
      &#039;&#039;&#039;And&#039;&#039;&#039; I add a &amp;quot;Forum&amp;quot; to section &amp;quot;1&amp;quot; and I fill the form with:&lt;br /&gt;
        | Forum name | Test forum name |&lt;br /&gt;
        | Forum type | Standard forum for general use |&lt;br /&gt;
        | Description | Test forum description |&lt;br /&gt;
      &#039;&#039;&#039;When&#039;&#039;&#039; I add a new discussion to &amp;quot;Test forum name&amp;quot; forum with:&lt;br /&gt;
        | Subject | Forum post subject |&lt;br /&gt;
        | Message | This is the body |&lt;br /&gt;
      &#039;&#039;&#039;Then&#039;&#039;&#039; I should see &amp;quot;Test forum name&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Note that:&lt;br /&gt;
&lt;br /&gt;
* Each scenario is executed in an isolated testing environment, so the first step begins with an empty moodle site and what you set up in an scenario (like the &#039;&#039;Test forum name&#039;&#039; forum in the example above) is cleaned up after the scenario execution&lt;br /&gt;
* The prefixes &amp;quot;Given&amp;quot;, &amp;quot;When&amp;quot; and &amp;quot;Then&amp;quot; are only informative and they are used to define the context (Given), specify the action (When) and check the results (Then), using them properly helps to understand what the scenario is testing.&lt;br /&gt;
&lt;br /&gt;
== Quick start ==&lt;br /&gt;
&lt;br /&gt;
This is a quick introduction to write a functional test (acceptance tests) using steps in a development/testing site, please DON&#039;T USE THIS IN A PRODUCTION SITE.&lt;br /&gt;
&lt;br /&gt;
To let you experience the pleasure of watching a feature file doing &amp;quot;your work&amp;quot; automatically in a real browser, this guide includes 2 optional steps to download Selenium and run it in another CLI.&lt;br /&gt;
&lt;br /&gt;
# Open a command line interface (you might need to run as administrator to get curl to work - one windows, right click the command prompt and &#039;choose run as administrator&#039;)&lt;br /&gt;
# &#039;&#039;&#039;cd /to/your/moodle/dirroot&#039;&#039;&#039;&lt;br /&gt;
# Edit config.php adding the following lines before the lib/setup.php include&lt;br /&gt;
#: &amp;lt;code language=&amp;quot;text&amp;quot;&amp;gt;$CFG-&amp;gt;behat_prefix = &#039;b_&#039;;&lt;br /&gt;
$CFG-&amp;gt;behat_dataroot = &#039;/path/to/your/behat/dataroot/directory&#039;;&lt;br /&gt;
$CFG-&amp;gt;behat_wwwroot = &#039;http://127.0.0.1&#039;; // must be different from wwwroot&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
# &#039;&#039;&#039;curl http://getcomposer.org/installer | php&#039;&#039;&#039; (If you get a curl error saying &#039;curl is not recognized as an internal or external command&#039; run the command line as administrator. In case you still have problems read https://docs.moodle.org/dev/Acceptance_testing#Installation)&lt;br /&gt;
# &#039;&#039;&#039;php admin/tool/behat/cli/init.php&#039;&#039;&#039; (If you get a curl error saying &#039;curl is not recognized as an internal or external command&#039; run the command line as administrator.)&lt;br /&gt;
# Download selenium-server-standalone-2.NN.N.jar from http://seleniumhq.org/download/, under &amp;quot;Selenium server (formerly the Selenium RC Server)&amp;quot;&lt;br /&gt;
# Open another command line interface and run &#039;&#039;&#039;java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;vendor/bin/behat --config /path/to/your/behat/dataroot/directory/behat/behat.yml&#039;&#039;&#039;&lt;br /&gt;
# You just ran the current Moodle tests, now let&#039;s add your own test, add a blog entry for example&lt;br /&gt;
# Browse to your $CFG-&amp;gt;behat_wwwroot, this is an empty test site and it is reset before each test (called scenario)&lt;br /&gt;
# From this point follow the steps you would follow to add manually a blog entry (login credentials are admin/admin)&lt;br /&gt;
# When you are done go to &#039;Site administration&#039; -&amp;gt; &#039;Development&#039; -&amp;gt; &#039;Acceptance testing&#039;, you will find the list of &amp;quot;actions&amp;quot; that can be run automatically, you can filter them to find what do you need to do (more steps can be added if you need, more info in https://docs.moodle.org/dev/Acceptance_testing#Adding_steps_definitions)&lt;br /&gt;
# To &#039;add a blog entry&#039; we need to:&lt;br /&gt;
## Log in the system as a valid user&lt;br /&gt;
## Expand &#039;My profile&#039; node of the navigation block&lt;br /&gt;
## Expand the &#039;Blogs&#039; node of the navigation block&lt;br /&gt;
## Follow he &#039;Add a new entry&#039; link&lt;br /&gt;
## Fill the moodle form with values for &#039;Entry title&#039; and &#039;Blog entry body&#039;&lt;br /&gt;
## Press the &#039;Save changes&#039; button&lt;br /&gt;
## Verify you see the values you entered in the form and verify you are not in the form page&lt;br /&gt;
# This translated to steps is:&lt;br /&gt;
#: &amp;lt;code language=&amp;quot;text&amp;quot;&amp;gt;Given I log in as &amp;quot;admin&amp;quot;&lt;br /&gt;
And I expand &amp;quot;My profile&amp;quot; node&lt;br /&gt;
And I expand &amp;quot;Blogs&amp;quot; node&lt;br /&gt;
And I follow &amp;quot;Add a new entry&amp;quot;&lt;br /&gt;
And I set the following fields to these values:&lt;br /&gt;
  | Entry title | I&#039;m the name |&lt;br /&gt;
  | Blog entry body | I&#039;m the description |&lt;br /&gt;
When I press &amp;quot;Save changes&amp;quot;&lt;br /&gt;
Then I should see &amp;quot;User Blog&amp;quot;&lt;br /&gt;
And I should see &amp;quot;I&#039;m the description&amp;quot;&lt;br /&gt;
And I should not see &amp;quot;Required&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
# We need to wrap this steps following the behavior driven development guidelines (more info in https://docs.moodle.org/dev/Acceptance_testing#Writing_features)&lt;br /&gt;
#: &amp;lt;code language=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
@core @core_blog&lt;br /&gt;
Feature: Add a blog entry&lt;br /&gt;
  In order to let the world know about me&lt;br /&gt;
  As a user&lt;br /&gt;
  I need to write blog entries&lt;br /&gt;
&lt;br /&gt;
  @javascript&lt;br /&gt;
  Scenario: Add a blog entry with valid data&lt;br /&gt;
    Given I log in as &amp;quot;admin&amp;quot;&lt;br /&gt;
    And I expand &amp;quot;My profile&amp;quot; node&lt;br /&gt;
    And I expand &amp;quot;Blogs&amp;quot; node&lt;br /&gt;
    And I follow &amp;quot;Add a new entry&amp;quot;&lt;br /&gt;
    And I fill the moodle form with:&lt;br /&gt;
      | Entry title | I&#039;m the name |&lt;br /&gt;
      | Blog entry body | I&#039;m the description |&lt;br /&gt;
    When I press &amp;quot;Save changes&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;View all of my entries&amp;quot;&lt;br /&gt;
    And I should see &amp;quot;I&#039;m a description&amp;quot;&lt;br /&gt;
    And I should not see &amp;quot;Required&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
# And save it into a file, in this case &#039;&#039;&#039;blog/tests/behat/add_entry.feature&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;php admin/tool/behat/cli/util.php --enable&#039;&#039;&#039;  (This will update the available tests and steps definitions)&lt;br /&gt;
# &#039;&#039;&#039;vendor/bin/behat --config /path/to/your/behat/dataroot/directory/behat/behat.yml --tags @core_blog&#039;&#039;&#039;&lt;br /&gt;
# Selenium will open a browser (firefox by default) and you will see how the steps you have been writting are executed&lt;br /&gt;
&lt;br /&gt;
You can also try to expand non existing nodes or change the &#039;Then&#039; assertions to get a beautiful failure.&lt;br /&gt;
&lt;br /&gt;
For detailed steps and/or troubleshooting:&lt;br /&gt;
* https://docs.moodle.org/dev/Acceptance_testing#Running_tests&lt;br /&gt;
* https://docs.moodle.org/dev/Acceptance_testing#Writing_features&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
* PHP 5.4 (see https://docs.moodle.org/dev/Acceptance_testing#Advanced_usage for PHP 5.3, only for non-production sites)&lt;br /&gt;
* Other dependencies are managed by the composer installer&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
* Edit config.php&lt;br /&gt;
** Use $CFG-&amp;gt;behat_dataroot to set the directory where behat test environment dataroot will be stored, something like &#039;&#039;&#039;$CFG-&amp;gt;behat_dataroot = &#039;/your/directory/path&#039;;&#039;&#039;&#039;. Ensure the directory can be created or have write permissions&lt;br /&gt;
** Use $CFG-&amp;gt;behat_prefix to set the database prefix of the behat test environment database tables, something like &#039;&#039;&#039;$CFG-&amp;gt;behat_prefix = &#039;behat_&#039;;&#039;&#039;&#039;&lt;br /&gt;
** Use $CFG-&amp;gt;behat_wwwroot to set address to be used to access behat instance. It has to be different from $CFG-&amp;gt;wwwroot, you can use for example localhost, 127.0.0.1 or any custom local host name specified in you /etc/hosts. If you use the built-in PHP server use &amp;quot;http://localhost:8000&amp;quot; or the value you set when you started it.&lt;br /&gt;
* Download composer&lt;br /&gt;
** &#039;&#039;&#039;cd /your/moodle/dirroot&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;curl http://getcomposer.org/installer | php&#039;&#039;&#039;&lt;br /&gt;
*** If you don&#039;t have curl installed or you have problems running &#039;&#039;&#039;curl http://getcomposer.org/installer | php&#039;&#039;&#039;:&lt;br /&gt;
**** Download &#039;&#039;&#039;http://getcomposer.org/installer&#039;&#039;&#039;&lt;br /&gt;
**** Store it in /your/moodle/dirroot/composerinstaller.php for example&lt;br /&gt;
**** Run it from /your/moodle/dirroot with &#039;&#039;&#039;php composerinstaller.php&#039;&#039;&#039;, you can delete this file after running the next step (&#039;&#039;&#039;php composer.phar update --dev&#039;&#039;&#039;)&lt;br /&gt;
* Install behat dependencies and enable the test environment&lt;br /&gt;
** &#039;&#039;&#039;cd /your/moodle/dirroot&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;php admin/tool/behat/cli/init.php&#039;&#039;&#039;&lt;br /&gt;
* (Optional) If you want to run tests that involves Javascript (most of them) you will also need Selenium&lt;br /&gt;
** Download it from http://seleniumhq.org/download/, named &amp;quot;Selenium server (formerly the Selenium RC Server)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Verify your installation ==&lt;br /&gt;
* Test your installation by browsing your /admin/tool/behat/index.php page.&lt;br /&gt;
If you are using MAMP/WAMP/XAMPP and don&#039;t get the report working... then you need to ensure that your web servers knows where the PHP executable (commad line) is. To do that, edit the &amp;quot;envvars&amp;quot; file (usually under library/bin) and add to $PATH the path to your php executable. Then restart the apache server and try again.&lt;br /&gt;
For example, for MAMP you probably need to add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
# Adding MAMP binaries communicate where CLI is&lt;br /&gt;
PATH=&amp;quot;/Applications/MAMP/bin/php/php5.x.y/bin:$PATH&amp;quot;; export PATH &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
at the end of MAMP/Library/bin/envvars.&lt;br /&gt;
&lt;br /&gt;
== Running tests ==&lt;br /&gt;
# (Optional) Start the PHP built-in web server if you configured the $CFG-&amp;gt;behat_wwwroot to use it:&lt;br /&gt;
#* Open a command line interface and &#039;&#039;&#039;cd /to/your/moodle/dirroot&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;&#039;php -S localhost:8000&#039;&#039;&#039; (This is the test site URL that moodle uses by default, if you want to use another one you can override it in config.php with $CFG-&amp;gt;behat_wwwroot attribute; more info in https://docs.moodle.org/dev/Acceptance_testing#Advanced_usage or config-dist.php)&lt;br /&gt;
# (Optional) Start the Selenium server (in case you want to run tests that involves Javascript)&lt;br /&gt;
#* (See http://www.installationpage.com/selenium/how-to-run-selenium-headless-firefox-in-ubuntu/ for running &#039;headless&#039; Firefox and xvfm in a server environment)&lt;br /&gt;
#* Open another command line interface and &#039;&#039;&#039;java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar&#039;&#039;&#039;&lt;br /&gt;
# Initialise Behat environment&lt;br /&gt;
#* To initialise behat use following command with optional parameters.&lt;br /&gt;
#** &#039;&#039;&#039;php admin/tool/behat/cli/init.php&#039;&#039;&#039;&lt;br /&gt;
#* Following options can be passed to initialisation command&lt;br /&gt;
#** &#039;&#039;&#039;-j, --parallel&#039;&#039;&#039;      Number of parallel behat run to initialise&lt;br /&gt;
#** &#039;&#039;&#039;-m, --maxruns&#039;&#039;&#039;  Max parallel processes to be executed at one time.&lt;br /&gt;
#** &#039;&#039;&#039;--fromrun&#039;&#039;&#039;         Execute run starting from (Used for parallel runs on different vms)&lt;br /&gt;
#** &#039;&#039;&#039;--torun&#039;&#039;&#039;             Execute run till (Used for parallel runs on different vms)&lt;br /&gt;
#** &#039;&#039;&#039;-h, --help&#039;&#039;&#039;         Print out this help&lt;br /&gt;
#* Example to initialise behat to run 4 process (Moodle CLI only supports {option}={value}, and not spaces) &lt;br /&gt;
#** &#039;&#039;&#039;php admin/tool/behat/cli/init.php -j=4&#039;&#039;&#039;&lt;br /&gt;
# Run Behat&lt;br /&gt;
#*  If behat site is initialise without parallel options then use following command:  &lt;br /&gt;
#** &#039;&#039;&#039;vendor/bin/behat --config /path/to/your/CFG_behat_dataroot/behat/behat.yml&#039;&#039;&#039; (For more options &#039;&#039;&#039;vendor/bin/behat --help&#039;&#039;&#039; or http://docs.behat.org/guides/6.cli.html)&lt;br /&gt;
#* If behat site is initialise with parallel options then use following command:&lt;br /&gt;
#** &#039;&#039;&#039;php admin/tool/behat/cli/run.php&#039;&#039;&#039; (For more options &#039;&#039;&#039;php admin/tool/behat/cli/run.php --help&#039;&#039;&#039;)&lt;br /&gt;
#* In case you don&#039;t want to run Javascript tests, use the Behat tags option to skip them, &#039;&#039;&#039;--tags=&amp;quot;~@javascript&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
#* In case you want to run specific scenario, use the Behat name option to run it, &#039;&#039;&#039;--name=&amp;quot;Filter user accounts by role and cohort&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
#* In case you want to run specific feature file, use the Behat feature option to run it, &#039;&#039;&#039;--feature=&amp;quot;/PATH/TO/MOODLE/admin/tests/behat/filter_users.feature&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
#* If you followed all the steps and you receive an unknown weird error probably your system&#039;s Firefox version is not compatible with the Selenium version you are running, try downloading the latest Selenium release from it&#039;s website as explained above&lt;br /&gt;
# (Optional) If you are adding new tests or steps definitions update the tests list:&lt;br /&gt;
#* &#039;&#039;&#039;php admin/tool/behat/cli/util.php --enable&#039;&#039;&#039;&lt;br /&gt;
# (Optional) Disable test environment (if you want to prevent access to test environment)&lt;br /&gt;
#* &#039;&#039;&#039;php admin/tool/behat/cli/util.php --disable&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note that if you have the HTTP_PROXY environment variable set, which you may have had to do to run composer, then you also need to set NO_PROXY=localhost.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Tests filters ===&lt;br /&gt;
With the &#039;&#039;&#039;--tags&#039;&#039;&#039; or the &#039;&#039;&#039;-name&#039;&#039;&#039; Behat options you can filter which tests are going to run or which ones are going to be skipped. There are a few tags that you might be interested in:&lt;br /&gt;
* &#039;&#039;&#039;@javascript&#039;&#039;&#039;: All the tests that runs in a browser using Javascript; they require Selenium to be running, otherwise an exception will be thrown.&lt;br /&gt;
* &#039;&#039;&#039;@_file_upload&#039;&#039;&#039;: All the tests that involves file uploading or any OS feature that is not 100% part of the browser. They should only be executed when Selenium is running in the same machine where the tests are running.&lt;br /&gt;
* &#039;&#039;&#039;@_alert&#039;&#039;&#039;: All the tests that involves Javascript dialogs (alerts, confirms...) are using a feature that is OS-dependant and out of the browser scope, so they should be tag appropriately as not all browsers manage them properly.&lt;br /&gt;
* &#039;&#039;&#039;@_switch_window&#039;&#039;&#039;: All the tests that are using the &#039;&#039;&#039;I switch to &amp;quot;NAME&amp;quot; window&#039;&#039;&#039; step should be tagged as not all browsers manage them properly.&lt;br /&gt;
* &#039;&#039;&#039;@_switch_iframe&#039;&#039;&#039;: All the tests that are using the &#039;&#039;&#039;I switch to &amp;quot;NAME&amp;quot; window&#039;&#039;&#039; steps should be tagged as it is an advanced feature and some browsers may have problems dealing with them&lt;br /&gt;
* &#039;&#039;&#039;@_cross_browser&#039;&#039;&#039;: All the tests that should run against multiple combinations of browsers + OS in a regular basis. The features that are sensitive to different combinations of OS and browsers should be tagges as @_cross_browser.&lt;br /&gt;
* &#039;&#039;&#039;@componentname&#039;&#039;&#039;: Moodle features uses the [https://docs.moodle.org/dev/Frankenstyle Frankenstyle] component name to tag the features according to the Moodle subsystem they belong to.&lt;br /&gt;
&lt;br /&gt;
=== Output formats ===&lt;br /&gt;
&lt;br /&gt;
If you want to see the failures immediately (rather than waiting ~3 hours for all the tests to finish) then either use the -v option to output a bit more information, or change the output format using --format. Format &#039;pretty&#039; (&#039;&#039;&#039;-f pretty&#039;&#039;&#039;) is sufficient for most cases, as it outputs each step outcomes in the command line making easier to see the progress.&lt;br /&gt;
&lt;br /&gt;
== Run behat using different browsers ==&lt;br /&gt;
&lt;br /&gt;
Following these instructions you can run behat in Firefox browser through Selenium, but you can run behat using different browsers through Selenium and even use phantomjs (Webkit). [[Acceptance_testing/Browsers|More info]]&lt;br /&gt;
&lt;br /&gt;
== Advanced usage ==&lt;br /&gt;
There are a few settings for advanced use of Behat and execution in continuous integration systems, by default all this options are disabled, use this settings only if you know what you are doing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Different test server URL&#039;&#039;&#039;. If for example your are interested in allowing accesses from your local network because your Jenkins server is there you can set $CFG-&amp;gt;behat_wwwroot to &#039;&#039;&#039;http://my.computer.local.ip:8000&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Behat configuration&#039;&#039;&#039;, Moodle writes a behat.yml config file with info about the available tests and steps definitions along with other Behat parameters, you can override the Behat parameters we set and add your new parameters, your parameters will be merged with the Moodle ones giving priority to your values in case of conflict. This is useful for an advanced use of Behat, with multiple profiles, output formats, integration with continuous servers... &lt;br /&gt;
* &#039;&#039;&#039;Save screenshots of failures&#039;&#039;&#039;. You can use $CFG-&amp;gt;behat_faildump_path to specify a directory where behat will generate a screenshot with the browser state each time a scenario fails. This is useful to detect where the problem was and work on a solution.&lt;br /&gt;
* &#039;&#039;&#039;Running with a browser other than Firefox&#039;&#039;&#039;, by adding the following code to your config.php you can change the selected browser that is run when behat is invoked. In this case Chrome is selected, but internet explorer, firefox, iphone, android, chrome, htmlunit should be valid options. You will need to run &#039;&#039;&#039;php admin/tool/behat/cli/init.php&#039;&#039;&#039; for changes to take effect.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code language=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$CFG-&amp;gt;behat_config = array(&lt;br /&gt;
    &#039;default&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;extensions&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;Behat\MinkExtension\Extension&#039; =&amp;gt; array(&lt;br /&gt;
                &#039;selenium2&#039; =&amp;gt; array(&lt;br /&gt;
                    &#039;browser&#039; =&amp;gt; &#039;chrome&#039;&lt;br /&gt;
                )&lt;br /&gt;
            )&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Note that for Chrome, you will need the Selenium Chrome Driver (https://code.google.com/p/selenium/wiki/ChromeDriver), and it will need to be installed in the command search path.&lt;br /&gt;
* &#039;&#039;&#039;Switch completely to test environment&#039;&#039;&#039; option was removed in 2.7, it is recommended to always set $CFG-&amp;gt;behat_wwwroot even in older versions instead.&lt;br /&gt;
* Note that when using cloud-based systems that can make use of non-standard capabilities like Saucelabs, you might want to provide configuration attributes containing the &#039;&#039;&#039;&#039;-&#039;&#039;&#039;&#039; character, which is automatically converted to &#039;&#039;&#039;&#039;_&#039;&#039;&#039;&#039; by the Symfony configuration manager that Behat is making use of (@see Symfony\Component\Config\Definition\Processor::normalizeKeys()) a way to avoid this restriction is to, adding to the vars you set like &#039;&#039;&#039;&#039;max-duration&#039;&#039;&#039;&#039; add the same var replacing dashes for underscores, this way the configuration manager will maintain the attribute containing dashes.&lt;br /&gt;
* &#039;&#039;&#039;Extra allowed settings&#039;&#039;&#039;, moodle allows users to define many settings in config.php (see config-dist.php) when running the behat test site those settings are skipped to avoid interaction with the production environment, in case you are interested in allowing some of those extra settings to run the tests using a configuration similar to the one you are using in your production environment you can whitelist them adding them to $CFG-&amp;gt;behat_extraallowedsettings (see config-dist.php for examples).&lt;br /&gt;
You can find more info and examples of how to use this settings in the config-dist.php file included in the Moodle codebase.&lt;br /&gt;
&lt;br /&gt;
== Contributing ==&lt;br /&gt;
&lt;br /&gt;
You can contribute the effort to automatically test all of Moodle&#039;s functionalities, as described in the [[Acceptance_testing/Contributing_automated_tests| guide to contributing automated tests]]. Here you can find information about [[Acceptance_testing#Writing_features|how to write new features]] and [[Acceptance_testing#Adding_steps_definitions|how to write new step definitions]] if your changes requires a base change in the [https://github.com/moodlehq/moodle-behat-extension Moodle behat extension] you can find here how to do it following the integration workflow: [[Acceptance_testing/Contributing_to_Moodle_behat_extension]].&lt;br /&gt;
&lt;br /&gt;
== Writing features ==&lt;br /&gt;
&lt;br /&gt;
All Moodle components and plugins (including 3rd party plugins) can specify their tests in .feature files using all the available steps.&lt;br /&gt;
&lt;br /&gt;
Once you decided which functionality you want to specify as a feature you should:&lt;br /&gt;
# Select the most appropriate Moodle component to include your test and create a COMPONENTNAME/tests/behat/FEATURENAME.feature file&lt;br /&gt;
# Add a tag with the component name in Frankenstyle format (https://docs.moodle.org/dev/Frankenstyle) on the first line along with the plugin type or @core if it&#039;s a core subsystem&lt;br /&gt;
# Begin writing the user story of the feature, including in the &#039;As a ...&#039; statement the main beneficiary of the feature:&lt;br /&gt;
#: &amp;lt;code lang=&amp;quot;yaml&amp;quot;&amp;gt;@plugintype @plugintype_pluginname&lt;br /&gt;
Feature: FEATURENAME&lt;br /&gt;
  In order to ...    // Why this feature is useful&lt;br /&gt;
  As ...    // It can be &#039;an admin&#039;, &#039;a teacher&#039;, &#039;a student&#039;, &#039;a guest&#039;, &#039;a user&#039;, &#039;a tests writer&#039; and &#039;a developer&#039;&lt;br /&gt;
  I need to ...      // The feature we want&amp;lt;/code&amp;gt;&lt;br /&gt;
# From the beneficiary point of view, think of different scenarios to ensure the feature works as expected&lt;br /&gt;
# For each scenario you thought:&lt;br /&gt;
## Think of the initial context you need, for example &#039;&#039;1 course with 2 students on it and an assignment&#039;&#039;, and which steps do you need to follow (interacting with the browser) to verify the scenario works as expected&lt;br /&gt;
## What you are testing requires Javascript? Think only on the feature you are testing (for example if you want to test that you can view your profile you don&#039;t need Javascript to click on a link and assert against plain HTML, but if you want to test something related with the course&#039;s gradebook you might want to test it with Javascript)&lt;br /&gt;
## Check the steps list (more info in https://docs.moodle.org/dev/Acceptance_testing#Available_steps) and set the initial context data (see https://docs.moodle.org/dev/Acceptance_testing#Fixtures for more info) and the steps to follow to verify all works as it should work. &lt;br /&gt;
## The prefixes &#039;&#039;Given&#039;&#039;, &#039;&#039;When&#039;&#039; and &#039;&#039;Then&#039;&#039; separates the scenario in 3 parts, the initial context setup (&#039;&#039;Given&#039;&#039;), the action that provokes a change in the system (&#039;&#039;When&#039;&#039;) and the validation of that change outcomes (&#039;&#039;Then&#039;&#039;) So with a quick view at the scenario you can see what it is testing as the prefixes will be something like Given -&amp;gt; And -&amp;gt; And -&amp;gt; When -&amp;gt; And -&amp;gt; And -&amp;gt; Then -&amp;gt; And -&amp;gt; And -&amp;gt; And. Once we begin with the first &#039;&#039;Then&#039;&#039; we can consider that we are checking the outcomes so all the steps from there should be prefixed with &#039;&#039;Then&#039;&#039;&lt;br /&gt;
## Copy the list of steps to the .feature file with the Scenario header:&lt;br /&gt;
##: &amp;lt;code lang=&amp;quot;yaml&amp;quot;&amp;gt;Scenario: Short description of the scenario&lt;br /&gt;
  Given step 1&lt;br /&gt;
  And step 2&lt;br /&gt;
  And step 3&lt;br /&gt;
  When step 4&lt;br /&gt;
  And step 5&lt;br /&gt;
  Then step 6&amp;lt;/code&amp;gt;&lt;br /&gt;
## If the steps you are using requires Javascript add the @javascript tag above the &amp;quot;Scenario:&amp;quot; headline&lt;br /&gt;
##:    &amp;lt;code lang=&amp;quot;yaml&amp;quot;&amp;gt;@javascript&lt;br /&gt;
Scenario: Short description of the scenario&lt;br /&gt;
  ...&lt;br /&gt;
  ...&amp;lt;/code&amp;gt;&lt;br /&gt;
# Run the tests, when creating your new features/scenarios you can specify a &#039;@wip&#039; (work in progress) tag in both the line above the Scenario description and the tests runner (vendor/bin/behat) to execute only the new scenario instead of running the whole set of tests.&lt;br /&gt;
# Add extra tags to the scenario or the feature if required according to https://docs.moodle.org/dev/Acceptance_testing#Tests_filters&lt;br /&gt;
&lt;br /&gt;
=== Available steps ===&lt;br /&gt;
&lt;br /&gt;
Moodle provides a interface to list and filter the steps you can use when writing features. You can access it through the Administration block, following &#039;&#039;&#039;Site Administration&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;Development&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;Acceptance testing&#039;&#039;&#039;. It allows filtering by keyword, by the Moodle component or by the type of step:&lt;br /&gt;
* Processes to set up the environment&lt;br /&gt;
* Actions that provokes an event&lt;br /&gt;
* Checkings to ensure the outcomes are the expected ones&lt;br /&gt;
&lt;br /&gt;
[[File:Acceptance_testing_UI_2.5.png]]&lt;br /&gt;
&lt;br /&gt;
* This interface only works on sites where Behat is installed. If you are using the local PHP server, for example, you can access it on that site at http://localhost:8000 (log in as admin/admin).&lt;br /&gt;
&lt;br /&gt;
=== Tips ===&lt;br /&gt;
* You can use a &#039;&#039;&#039;Background&#039;&#039;&#039; section before the &#039;&#039;&#039;Scenario&#039;&#039;&#039; sections, this steps will be executed before the steps of each scenario (http://docs.behat.org/guides/1.gherkin.html#backgrounds)&lt;br /&gt;
* You can use &#039;&#039;&#039;Scenario outlines&#039;&#039;&#039; if your scenarios are nearly the same and depends on a few vars; check out the link for an explicative example (http://docs.behat.org/guides/1.gherkin.html#scenario-outlines)&lt;br /&gt;
** If your scenario outline consists of many steps it may be useful to add a comment with the number of steps. If the the test fails behat will tell you in which step overall and you will have to divide by the number of steps of the scenario to know in which example. &lt;br /&gt;
* Is better to test the outcomes against the given data than against language strings, which are depending on the selected language.&lt;br /&gt;
* In case you need to interact with popup windows you need to switch to the window you want to interact with after opening it using the &#039;&#039;&#039;I switch to &amp;quot;popupwindowname&amp;quot; window&#039;&#039;&#039;, close it when you finish interacting with it and return to the main window using &#039;&#039;&#039;I switch to main window&#039;&#039;&#039;&lt;br /&gt;
* The format of the .feature files is YAML which finds out the data hierarchy from the indentation of it&#039;s elements, so be sure that the elements are correctly nested and the indentation is correct using spaces when necessary&lt;br /&gt;
&lt;br /&gt;
=== Providing values to steps ===&lt;br /&gt;
Most of the steps requires values, there are five methods to provide values to steps, the method depends on the step specification, you can know when a steps requires a value because you will see a drop down menu with a closed list of options that the step accepts as argument or an upper case string between double quotes, something like &#039;&#039;&#039;I press &amp;quot;BUTTON_STRING&amp;quot;&#039;&#039;&#039; or it ends with a &#039;&#039;&#039;:&#039;&#039;&#039; . The five methods are:&lt;br /&gt;
* &#039;&#039;&#039;A string/text&#039;&#039;&#039;; is the most common case, the texts are wrapped between double quotes (&amp;quot; character) you have to replace the info about the expected value for your value; for example something like &#039;&#039;&#039;I press &amp;quot;BUTTON_STRING&amp;quot;&#039;&#039;&#039; should become &#039;&#039;&#039;I press &amp;quot;Save and return to course&amp;quot;&#039;&#039;&#039;. If you want to add a string which contains a &amp;quot; character, you can escape it with \&amp;quot;, for example &#039;&#039;&#039;I fill the &amp;quot;Name&amp;quot; field with &amp;quot;Alan alias \&amp;quot;the legend\&amp;quot;&amp;quot;&#039;&#039;&#039;. You can identify this steps because they ends with &#039;&#039;&#039;_STRING&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;A number&#039;&#039;&#039;; some steps requires numbers as values, to be more specific an undetermined number of digits from 0 to 9 (Natural numbers + 0) you can identify them because the expected value info string ends with &#039;&#039;&#039;_NUMBER&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;A table&#039;&#039;&#039;; is a relation between values, the most common use of it is to fill forms. The steps which requires tables are easily identifiable because they finish with &#039;&#039;&#039;:&#039;&#039;&#039; The steps description gives info about what the table columns must contain, for example &#039;&#039;&#039;Fills a moodle form with field/value data&#039;&#039;&#039;. Here you don&#039;t need to escape the double quotes if you want to include them as part of the value.&lt;br /&gt;
* &#039;&#039;&#039;A PyString&#039;&#039;&#039;; is a multiline string, most commonly used to fill out forms when a newline is required. Like steps with tables, steps which require PyStrings will end with &amp;quot;:&amp;quot;&lt;br /&gt;
* &#039;&#039;&#039;A field value&#039;&#039;&#039;; There are many different field types, if an argument requires a field value the expected value will depend on the field type:&lt;br /&gt;
** Text-based fields: It expects the text. This includes textareas, input type text, input type password...&lt;br /&gt;
** Checkbox: It expects 1 to check and for checked and &amp;quot;&amp;quot; to uncheck or for unchecked&lt;br /&gt;
** Select: It expects the option text or the option value. In case you interact with a multi-select you should specify the options separating them with commas. For example: &#039;&#039;&#039;option1, option2, option3&#039;&#039;&#039;&lt;br /&gt;
** Radio: The text of the radio option&lt;br /&gt;
* &#039;&#039;&#039;A selector&#039;&#039;&#039;; there are steps that can be used with different kinds of elements, for example &#039;&#039;&#039;I click on &amp;quot;User Name&amp;quot; &amp;quot;link&amp;quot;&#039;&#039;&#039; or &#039;&#039;&#039;I click on &amp;quot;User Name&amp;quot; &amp;quot;button&amp;quot;&#039;&#039;&#039; this is a closed list of elements, they always works together with another argument, where you specify the locator (eg. the link text in a link) In the &#039;Acceptance testing&#039; interface you can see a drop-down menu to select one of these options:&lt;br /&gt;
** field - for searching a field by its id, name, value or label&lt;br /&gt;
** link - for searching a link by its href, id, title, img alt or value&lt;br /&gt;
** button - for searching a button by its name, id, value, img alt or title&lt;br /&gt;
** link_or_button - for searching for both, links and buttons&lt;br /&gt;
** select - for searching a select field by its id, name or label&lt;br /&gt;
** checkbox - for searching a checkbox by its id, name, or label&lt;br /&gt;
** radio - for searching a radio button by its id, name, or label&lt;br /&gt;
** file - for searching a file input by its id, name, or label&lt;br /&gt;
** optgroup - for searching optgroup by its label&lt;br /&gt;
** option - for searching an option by its content&lt;br /&gt;
** dialogue - for searching a dialogue with the specified header text&lt;br /&gt;
** filemanager - for searching a filemanager by it&#039;s id or label&lt;br /&gt;
** block - for searching a Moodle block by it&#039;s English name or it&#039;s frankenstyle name&lt;br /&gt;
** section - for searching for a section on a course page by it&#039;s title or its written out date (e.g. &amp;quot;1 January - 7 January&amp;quot;). Use &amp;quot;frontpage&amp;quot; &amp;quot;section&amp;quot; for the frontpage section if it has no title (default)&lt;br /&gt;
** activity - for searching for an activity module in a course list by it&#039;s title&lt;br /&gt;
** region - for searching a Moodle page region with that id, in fact it works with all the page&#039;s ids&lt;br /&gt;
** table_row - for searching a table row which contains the specified text&lt;br /&gt;
** table - for searching a table by its id or caption&lt;br /&gt;
** fieldset - for searching a fieldset by it&#039;s id or legend&lt;br /&gt;
** css_element - for searching an element by its CSS selector&lt;br /&gt;
** xpath_element - for searching an element by its XPath&lt;br /&gt;
* &#039;&#039;&#039;A text selector&#039;&#039;&#039;; similar to a selector but those are the elements that returns an area of the DOM, they are useful in steps following the format &#039;&#039;&#039;... in the &amp;quot;Community finder&amp;quot; &amp;quot;block&amp;quot;&#039;&#039;&#039; where you are clicking or looking for some text inside a specific area. In the &#039;Acceptance testing&#039; interface you can see a drop-down menu to select one of these options:&lt;br /&gt;
** dialogue - for searching a dialogue with the specified header text&lt;br /&gt;
** block - for searching a Moodle block by it&#039;s English name or it&#039;s frankenstyle name&lt;br /&gt;
** section - for searching for a section on a course page by it&#039;s title or its written out date (e.g. &amp;quot;1 January - 7 January&amp;quot;). Use &amp;quot;frontpage&amp;quot; &amp;quot;section&amp;quot; for the frontpage section if it has no title (default)&lt;br /&gt;
** activity - for searching for an activity module in a course list by it&#039;s title&lt;br /&gt;
** region - for searching a Moodle page region with that id, in fact it works with all the page&#039;s ids&lt;br /&gt;
** table_row - for searching a table row which contains the specified text&lt;br /&gt;
** table - for searching a table by its id or caption&lt;br /&gt;
** fieldset - for searching a fieldset by it&#039;s id or legend&lt;br /&gt;
** css_element - for searching an element by its CSS selector&lt;br /&gt;
** xpath_element - for searching an element by its XPath&lt;br /&gt;
&lt;br /&gt;
==== Uploading files ====&lt;br /&gt;
Note than some tests requires files to be uploaded, in this case&lt;br /&gt;
* The &#039;&#039;&#039;I upload &amp;quot;FILEPATH_STRING&amp;quot; file to &amp;quot;FILEPICKER_FIELD_STRING&amp;quot; filepicker&#039;&#039;&#039; step can be used when located in the form page&lt;br /&gt;
* The file to upload should be included along with the Moodle codebase in COMPONENTNAME/tests/fixtures/*&lt;br /&gt;
* The file to upload is specified by it&#039;s path, which should be relative to the codebase root (&#039;&#039;&#039;lib/tests/fixtures/users.csv&#039;&#039;&#039; for example) &lt;br /&gt;
* &#039;&#039;&#039;/&#039;&#039;&#039; should be used as directory separator and the file names can not include this &#039;&#039;&#039;/&#039;&#039;&#039; character as all of them would be converted to the OS-dependant directory separator to maintain the compatibility with Windows systems.&lt;br /&gt;
* The scenarios that includes files uploading should be tagged using the &#039;&#039;&#039;@_file_upload&#039;&#039;&#039; tag&lt;br /&gt;
&lt;br /&gt;
==== Checking table values ====&lt;br /&gt;
You can check if specific value exists or not in a table row/column by using:&lt;br /&gt;
* Then &amp;quot;STRING_IN_ROW&amp;quot; row &amp;quot;COLUMN_HEADER&amp;quot; column of &amp;quot;TABLE_ID&amp;quot; table should contain &amp;quot;VALUE_TO_CHECK&amp;quot;&lt;br /&gt;
* Then the following should exist in the &amp;quot;TABLE_ID&amp;quot; table:&lt;br /&gt;
    | COLUMN_HEADER1 | COLUMN_HEADER2 |&lt;br /&gt;
    | VALUE_IN_ROW_1 | VALUE_IN_ROW_1 |&lt;br /&gt;
    | VALUE_IN_ROW_2 | VALUE_IN_ROW_2 |&lt;br /&gt;
&lt;br /&gt;
=== Fixtures ===&lt;br /&gt;
&lt;br /&gt;
As seen in [[https://docs.moodle.org/dev/Acceptance_testing#Examples examples]] Moodle provides a way to quickly set up the contextual data (courses, users, enrolments...) that you need to properly test scenarios, this can be done using one of the site templates (TODO) or creating entities in the background section (common for all the steps) or in the &amp;quot;Given&amp;quot; part of your scenario. Note that this steps can only be used to set up the contextual data required to test the feature but they don&#039;t test what they are doing; for example, the &amp;quot;Given the following &amp;quot;users&amp;quot; exists&amp;quot; is not testing that Moodle is able to create a user, but to test that a user can add a blog entry you might want to use this step. For further info, acceptance tests are supposed to be black-boxed tests (the tester don&#039;t know about the internals of the application) and this steps are using internal Moodle data generators instead of running all the steps required to create a user or to create a course, which speeds up the test execution. There are other features to test that all this elements can be properly created.&lt;br /&gt;
&lt;br /&gt;
==== Available elements ====&lt;br /&gt;
Most of the available elements can only be created in relation to other elements, to hide the complexity of the Moodle internals (references by contexts, ids...) the references can be done using more human-friendly mappings. &lt;br /&gt;
&lt;br /&gt;
The examples below shows how to add elements referencing other elements, there are required fields to reference the elements, other attributes will be filled with random data if they are not specified.&lt;br /&gt;
&lt;br /&gt;
* Course categories&lt;br /&gt;
** The required field is idnumber&lt;br /&gt;
** References between parent/children by their idnumber, using the &amp;quot;category&amp;quot; field&lt;br /&gt;
  Given the following &amp;quot;categories&amp;quot; exist:&lt;br /&gt;
    | name       | category | idnumber |&lt;br /&gt;
    | Category 1 | 0        | CAT1     |&lt;br /&gt;
    | Category 2 | CAT1     | CAT2     |&lt;br /&gt;
&lt;br /&gt;
* Courses&lt;br /&gt;
** The required field is shortname&lt;br /&gt;
** Uses the category idnumber as category reference&lt;br /&gt;
  Given the following &amp;quot;courses&amp;quot; exist:&lt;br /&gt;
    | fullname | shortname | category | format | &lt;br /&gt;
    | Course 1 | COURSE1   | CAT1     | topics |&lt;br /&gt;
    | Course 2 | COURSE2   | CAT2     |        |&lt;br /&gt;
&lt;br /&gt;
* Activities *(note that this step does not work with all kind of activities, only the ones that have data generators)*&lt;br /&gt;
** The required fields are activity, course and idnumber&lt;br /&gt;
** Uses activity to specify the activity type&lt;br /&gt;
** Uses the course shortname as course reference&lt;br /&gt;
** Other activity-dependant fields can be specified by it&#039;s field name&lt;br /&gt;
  Given the following &amp;quot;activities&amp;quot; exist:&lt;br /&gt;
    | activity | course | idnumber | name                 | intro                       |&lt;br /&gt;
    | assign   | C1     | assign1  | Test assignment name | Test assignment description |&lt;br /&gt;
    | data     | C1     | data1    | Test database name   | Test database description   |&lt;br /&gt;
&lt;br /&gt;
* Groups&lt;br /&gt;
** The required fields are course and idnumber&lt;br /&gt;
** Uses the course shortname as course reference&lt;br /&gt;
  Given the following &amp;quot;groups&amp;quot; exist:&lt;br /&gt;
    | name    | description | course  | idnumber |&lt;br /&gt;
    | Group 1 | Anything    | COURSE1 | GROUP1   |&lt;br /&gt;
&lt;br /&gt;
* Groupings&lt;br /&gt;
** The required fields are course and idnumber&lt;br /&gt;
** Uses the course shortname as course reference&lt;br /&gt;
  Given the following &amp;quot;groupings&amp;quot; exist:&lt;br /&gt;
    | name       | course  | idnumber  |&lt;br /&gt;
    | Grouping 1 | COURSE1 | GROUPING1 |&lt;br /&gt;
    | Grouping 2 | COURSE1 | GROUPING2 |&lt;br /&gt;
&lt;br /&gt;
* Users&lt;br /&gt;
** The required field is username (if password is not set username value will be used as password too)&lt;br /&gt;
  Given the following &amp;quot;users&amp;quot; exist:&lt;br /&gt;
    | username | email       | firstname | lastname |&lt;br /&gt;
    | testuser | asd@asd.com | Test      | User     |&lt;br /&gt;
&lt;br /&gt;
* Course enrolments&lt;br /&gt;
** The required fields are user, course and role&lt;br /&gt;
** Uses the course shortname as course reference&lt;br /&gt;
** Uses the user username as user reference&lt;br /&gt;
** Uses the role shortname as role reference&lt;br /&gt;
** Uses the enrolment name as enrol reference&lt;br /&gt;
  Given the following &amp;quot;course enrolments&amp;quot; exist:&lt;br /&gt;
    | user     | course  | role           | enrol  |&lt;br /&gt;
    | testuser | COURSE1 | editingteacher | manual |&lt;br /&gt;
&lt;br /&gt;
* Roles&lt;br /&gt;
** The required field is shortname&lt;br /&gt;
** Uses a one of the following roles as archetype: manager, coursecreator, editingteacher, teacher, student, guest, user and frontpage&lt;br /&gt;
  Given the following &amp;quot;roles&amp;quot; exist:&lt;br /&gt;
    | shortname | name          | description | archetype      |&lt;br /&gt;
    | custom1   | Custom Role 1 |             | editingteacher |&lt;br /&gt;
&lt;br /&gt;
* Role assigns&lt;br /&gt;
** The required fields are user, role, contextlevel and reference&lt;br /&gt;
** Uses the user username as user reference&lt;br /&gt;
** Uses the role shortname as role reference&lt;br /&gt;
** Uses contextlevel + reference to specify the context. See [[#Referencing_contexts]] for more info.&lt;br /&gt;
  Given the following &amp;quot;role assigns&amp;quot; exist:&lt;br /&gt;
    | user  | role           | contextlevel | reference |&lt;br /&gt;
    | user1 | manager        | System       |           |&lt;br /&gt;
    | user2 | editingteacher | Category     | CATEGORY1 |&lt;br /&gt;
    | user3 | editingteacher | Course       | COURSE1   |&lt;br /&gt;
&lt;br /&gt;
* System role assigns (deprecated in favour of role assigns, see item right above this one)&lt;br /&gt;
** The required fields are user and role&lt;br /&gt;
** Uses the user username as user reference&lt;br /&gt;
** Uses the role shortname as role reference&lt;br /&gt;
  Given the following &amp;quot;system role assigns&amp;quot; exist:&lt;br /&gt;
    | user     | role    |&lt;br /&gt;
    | testuser | manager |&lt;br /&gt;
&lt;br /&gt;
* Permission overrides&lt;br /&gt;
** The required fields are capability, permissions, role, and the contextlevel + it&#039;s reference&lt;br /&gt;
** Uses contextlevel + reference to specify the context. See [[#Referencing_contexts]] for more info.&lt;br /&gt;
  Given the following &amp;quot;permission overrides&amp;quot; exist:&lt;br /&gt;
    | capability            | permission | role           | contextlevel | reference |&lt;br /&gt;
    | mod/forum:editanypost | Allow      | student        | Course       | C1        |&lt;br /&gt;
    | mod/forum:replynews   | Prevent    | editingteacher | Course       | C1        |&lt;br /&gt;
    | mod/paquiro:sings     | Prohibit   | student        | System       |           |&lt;br /&gt;
&lt;br /&gt;
* Group members&lt;br /&gt;
** The required fields are user and group&lt;br /&gt;
** Uses the group idnumber as group reference&lt;br /&gt;
** Uses the user username as user reference&lt;br /&gt;
  Given the following &amp;quot;group members&amp;quot; exist:&lt;br /&gt;
    | user     | group  |&lt;br /&gt;
    | testuser | GROUP1 |&lt;br /&gt;
&lt;br /&gt;
* Grouping groups&lt;br /&gt;
** The required fields are grouping and group&lt;br /&gt;
** Uses the group idnumber as group reference&lt;br /&gt;
** Uses the grouping idnumber as grouping reference&lt;br /&gt;
  Given the following &amp;quot;grouping groups&amp;quot; exist:&lt;br /&gt;
    | grouping  | group  |&lt;br /&gt;
    | GROUPING1 | GROUP1 |&lt;br /&gt;
&lt;br /&gt;
* Cohorts&lt;br /&gt;
** The required field is idnumber&lt;br /&gt;
  Given the following &amp;quot;cohorts&amp;quot; exist:&lt;br /&gt;
    | name     | idnumber |&lt;br /&gt;
    | Cohort 1 | COHORT1  |&lt;br /&gt;
&lt;br /&gt;
==== Referencing contexts ====&lt;br /&gt;
&lt;br /&gt;
Moodle has different context levels, internally they have an identifier, but to reference them from steps we can use a more human way, using the level of the context (as specified below) and the reference, which will depend on the contextlevel we are using:&lt;br /&gt;
* contextlevel: &#039;&#039;&#039;System&#039;&#039;&#039;, &#039;&#039;&#039;User&#039;&#039;&#039;, &#039;&#039;&#039;Category&#039;&#039;&#039;, &#039;&#039;&#039;Course&#039;&#039;&#039; or &#039;&#039;&#039;Activity module&#039;&#039;&#039;&lt;br /&gt;
* reference:&lt;br /&gt;
** System: Nothing, just leave the the cell empty&lt;br /&gt;
** User: The user &#039;&#039;&#039;username&#039;&#039;&#039;&lt;br /&gt;
** Category: The category &#039;&#039;&#039;idnumber&#039;&#039;&#039;&lt;br /&gt;
** Course: The course &#039;&#039;&#039;shortname&#039;&#039;&#039;&lt;br /&gt;
** Activity module: The activity &#039;&#039;&#039;idnumber&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The data generators which makes use of these format are pointing to here.&lt;br /&gt;
&lt;br /&gt;
=== Features check list ===&lt;br /&gt;
* It&#039;s a new feature or a new scenario of an existing feature&lt;br /&gt;
* Is using the &#039;&#039;&#039;Background&#039;&#039;&#039; section or &#039;&#039;&#039;Scenario Outlines&#039;&#039;&#039; instead of duplicating steps (only when applicable)&lt;br /&gt;
* Are using the appropriate Moodle component tag according to https://docs.moodle.org/dev/Acceptance_testing#Tests_filters&lt;br /&gt;
* The user story of the feature includes a valid stakeholder and makes sense according to https://docs.moodle.org/dev/Acceptance_testing#Writing_features&lt;br /&gt;
* Covers both JS and non-JS environments&lt;br /&gt;
&lt;br /&gt;
== Adding steps definitions ==&lt;br /&gt;
&lt;br /&gt;
Each Moodle component and plugin (including 3rd party plugins) can add new steps definitions. If you are writing tests and you notice that you are repeating the same group of steps you might want to create a new step definition that allows you to substitute the group of steps for one single step, something like &#039;&#039;I add a forum post with &amp;quot;blablabla&amp;quot; as description&#039;&#039; for example; also you can create whole new steps using the APIs provided by Behat and Mink if what you need to do is not covered by any of the available steps.&lt;br /&gt;
&lt;br /&gt;
As commented in https://docs.moodle.org/dev/Acceptance_testing#Fixtures, this are black box tests, so we are not supposed to know about Moodle internals; translated to developer language it means don&#039;t use Moodle internals API calls, for example you should not try to cheat using a set_config() call, you should follow Moodle&#039;s user interface to reach the setting page and change it&#039;s value.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
&lt;br /&gt;
You can use this example below or any of the existing steps definitions as a template.&lt;br /&gt;
&lt;br /&gt;
* auth/tests/behat/behat_auth.php&lt;br /&gt;
  class behat_auth extends behat_base {&lt;br /&gt;
      /**&lt;br /&gt;
       * Logs in the user. There should exist a user with the same value as username and password&lt;br /&gt;
       *&lt;br /&gt;
       * This second comment line will be not shown in the steps definitions list as it is only&lt;br /&gt;
       * reading the first line in the comment block.&lt;br /&gt;
       *&lt;br /&gt;
       * @Given /^I log in as &amp;quot;(?P&amp;lt;username_string&amp;gt;(?:[^&amp;quot;]|\\&amp;quot;)*)&amp;quot;$/&lt;br /&gt;
       */&lt;br /&gt;
      public function i_log_in_as($username) {&lt;br /&gt;
          return array(new Given(&#039;I am on homepage&#039;),&lt;br /&gt;
              new Given(&#039;I follow &amp;quot;&#039; . get_string(&#039;login&#039;) . &#039;&amp;quot;&#039;),&lt;br /&gt;
              new Given(&#039;I fill in &amp;quot;&#039; . get_string(&#039;username&#039;) . &#039;&amp;quot; with &amp;quot;&#039; . $this-&amp;gt;escape($username) . &#039;&amp;quot;&#039;),&lt;br /&gt;
              new Given(&#039;I fill in &amp;quot;&#039; . get_string(&#039;password&#039;) . &#039;&amp;quot; with &amp;quot;&#039;. $this-&amp;gt;escape($username) . &#039;&amp;quot;&#039;),&lt;br /&gt;
              new Given(&#039;I press &amp;quot;&#039; . get_string(&#039;login&#039;) . &#039;&amp;quot;&#039;)&lt;br /&gt;
          );&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Tips ===&lt;br /&gt;
&lt;br /&gt;
If you are creating a completely new step definition there are also a few things to consider:&lt;br /&gt;
* Steps definitions should be compatible with both Javascript and non-Javascript tests, you can use $this-&amp;gt;running_javascript() to deal with both&lt;br /&gt;
* The definition code will be executed by Behat, not by Moodle, you have to keep this in mind for example when throwing exceptions, Behat exceptions will give more info to the user about where is the problem&lt;br /&gt;
** You can find these exceptions in &#039;&#039;&#039;vendor/behat/mink/src/Behat/Mink/Exception/*&#039;&#039;&#039;&lt;br /&gt;
* Selenium is fast, sometimes it tries to interact with DOM elements or tries to execute actions that requires JS that are not loaded or ready to used; this is why, sometimes and randomly, you can see an &amp;quot;element not found&amp;quot; failure&lt;br /&gt;
** The quickest way to solve this problem is using behat_base::find*() methods (where the * corresponds to &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;_all&#039;&#039;&#039;, or to a named selector preceded by &#039;&#039;&#039;_&#039;&#039;&#039;, http://mink.behat.org/#named-selectors) which only requires the locator as argument. This methods will wait for the requested element to be ready or return an exception if the element is not found after the timeout value expires, you can also force the timeout value, which defaults to 6 seconds. An example of a named selector use is &#039;&#039;&#039;$button = $this-&amp;gt;find_button(&amp;quot;Save changes&amp;quot;);&#039;&#039;&#039; if you are not sure about the element being available you always can wrap the find*() call in a try &amp;amp; catch.&lt;br /&gt;
** For advanced usages, the spin method is defined in &#039;&#039;&#039;lib/behat/behat_base::spin&#039;&#039;&#039;, consider that all the contents of the closures passed to spin() can be executed more than once, so don&#039;t use irreversible actions that can invalidate the tests results (for example use find() methods but don&#039;t use click() methods)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you create new steps definitions or tests you must run &#039;&#039;&#039;php admin/tool/behat/cli/util.php --enable&#039;&#039;&#039; to update the Behat config file before running &#039;&#039;&#039;vendor/bin/behat&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Check list ===&lt;br /&gt;
&lt;br /&gt;
New steps should be/have:&lt;br /&gt;
* Implemented as public methods of a PHP class whose name must begin with &#039;behat_&#039; prefix and with &#039;.php extension&lt;br /&gt;
* Using the class name as filename (adding the &#039;.php&#039; extension) and extending MOODLEDIRROOT/lib/behat/behat_base.php (or MOODLEDIRROOT/lib/behat/behat_files.php if it&#039;s a repository or is files-related)&lt;br /&gt;
* With a descriptive class name, for example the component name (it will be used when filtering steps definitions)&lt;br /&gt;
* Stored in COMPONENTNAME/tests/behat/ directory or lib/tests/behat/ if is not part of any other component&lt;br /&gt;
* Describe it&#039;s purpose in a single line inside the method doc comment, the size of the comment is not a problem&lt;br /&gt;
* Describe the regular expression with the most appropriate tag inside the method doc comment:&lt;br /&gt;
** &#039;&#039;&#039;@Given&#039;&#039;&#039; - A step to set up the initial context (for example &#039;&#039;the following &amp;quot;courses&amp;quot; exists&#039;&#039;)&lt;br /&gt;
** &#039;&#039;&#039;@When&#039;&#039;&#039; - An action that provokes an event (for example &#039;&#039;I press the button &amp;quot;buttonname&amp;quot;&#039;&#039;)&lt;br /&gt;
** &#039;&#039;&#039;@Then&#039;&#039;&#039; - Checkings to ensure the outcomes are the expected (for example &#039;&#039;I should see &amp;quot;whatever&amp;quot;&#039;&#039;)&lt;br /&gt;
* Depending on the inputs your definition expects you must use a different regular expression:&lt;br /&gt;
** &#039;&#039;&#039;If you expect a number:&#039;&#039;&#039; &amp;quot;(?P&amp;lt;info_about_what_you_expect_number&amp;gt;\d+)&amp;quot; (note that the regular expression is quoted between &#039;&#039;&#039;&amp;quot;&#039;&#039;&#039;)&lt;br /&gt;
** &#039;&#039;&#039;If you expect a string or a text:&#039;&#039;&#039; &amp;quot;(?P&amp;lt;info_about_what_you_expect_string&amp;gt;(?:[^&amp;quot;]|\\&amp;quot;)*)&amp;quot; Don&#039;t use &#039;&#039;&#039;text_selector_string&#039;&#039;&#039; and &#039;&#039;&#039;selector_string&#039;&#039;&#039; as info strings, they are reserved to selector types (note that the regular expression is quoted between &#039;&#039;&#039;&amp;quot;&#039;&#039;&#039;)&lt;br /&gt;
** &#039;&#039;&#039;If you expect a table with key/value pairs (for example to fill a form):&#039;&#039;&#039; Finish your regular expression with &#039;&#039;&#039;:&#039;&#039;&#039; and provide info in the description about the contents of the table&lt;br /&gt;
** &#039;&#039;&#039;If you expect a selector type:&#039;&#039;&#039; &amp;quot;(?P&amp;lt;selector_string&amp;gt;[^&amp;quot;]*)&amp;quot; or &amp;quot;(?P&amp;lt;text_selector_string&amp;gt;[^&amp;quot;]*)&amp;quot; depending on whether you want to use any selector or you want a text-based selector (more info about selectors in https://docs.moodle.org/dev/Acceptance_testing#Providing_values_to_steps)&lt;br /&gt;
* To make test writer&#039;s life better is good to include explicative info in the subexpressions of the regular expression about what the test writer is supposed to put in there (for example &#039;&#039;I expand &amp;quot;(?P&amp;lt;nodetext&amp;gt;(?:[^&amp;quot;]|\\&amp;quot;)*)&amp;quot; node&#039;&#039;)&lt;br /&gt;
* Is recommended to use the static part of the regular expression as the name of the method, using underscores instead of spaces (see current steps definitions)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== How can you tell if Selenium is running? ===&lt;br /&gt;
&lt;br /&gt;
Try going to http://localhost:4444/selenium-server/. If Selenium is not running, nothing will happen. You will get a time-out. If selenium is running, you will get a 404 error page saying powered by Jetty at the bottom.&lt;br /&gt;
&lt;br /&gt;
=== How can I stop Selenium? ===&lt;br /&gt;
&lt;br /&gt;
Go to the URL http://localhost:4444/selenium-server/driver/?cmd=shutDownSeleniumServer. I think when it works it outputs &amp;quot;OKOK&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== How to pause behat to check browser html ===&lt;br /&gt;
&lt;br /&gt;
You can use following step to pause behat execution. To resume execution, press Enter/Return key in console.&lt;br /&gt;
&amp;lt;pre&amp;gt;And I pause scenario execution&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Behat tells me that lots of steps are undefined ===&lt;br /&gt;
&lt;br /&gt;
You probably forgot the --config option in the behat command.&lt;br /&gt;
&lt;br /&gt;
== Browser specific fixes ==&lt;br /&gt;
&lt;br /&gt;
If you are interested in running behat in other browsers you might be interested on https://docs.moodle.org/dev/Acceptance_testing/Browsers&lt;br /&gt;
&lt;br /&gt;
When running acceptance tests in conjunction with Selenium against Chrome, IE, or Safari there is a fix for the navigation bar that gets applied in order to avoid errors arising from a bug in the webdrivers for those browsers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;The issue&amp;lt;/b&amp;gt;: When an acceptance test goes to interact with an element on the page it first ensures that the element in the view-port and if not scrolls the browser to get the element into the view-port. If you are running against Chrome, IE, or Safari the browser scrolls the element only just inside the view-port. It doesn&#039;t however allow for any fixed position elements such as the navigation bar.&lt;br /&gt;
What happens: In some situations these browsers scroll up to reach a button, however not enough as the button ends up behind the navigation bar and cannot be interacted with.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Our solution&amp;lt;/b&amp;gt;: We can not change browser driver behaviour so we have integrated a work around. When running acceptance tests against one of these browsers we change the position attribute of the navigation bar from fixed to absolute. This is not ideal as it is not how the user experiences the site, however it allows us to run the full acceptance test suite against these browsers so we allowed it. A notice will be displayed when you start an acceptance test run if the browser specific fixes have been applied. See MDL-47734 / MDL-45231 for more details.&lt;br /&gt;
&lt;br /&gt;
== See also == &lt;br /&gt;
&lt;br /&gt;
* Guidelines for contributors: [[Acceptance_testing/Contributing_automated_tests|Contributing automated tests]]&lt;br /&gt;
* Technical info: [[Behat integration]]&lt;br /&gt;
* Behat CLI command options: http://docs.behat.org/guides/6.cli.html&lt;br /&gt;
* How to use selectors to interact with the site elements: http://mink.behat.org/#traverse-the-page-selectors&lt;br /&gt;
* Vagrant profile with Moodle and Behat preconfigured: https://github.com/mackensen/moodle-hat&lt;br /&gt;
&lt;br /&gt;
[[Category:Behat]][[Category:Quality Assurance]]&lt;br /&gt;
&lt;br /&gt;
[[es:Prueba de aceptación]]&lt;/div&gt;</summary>
		<author><name>Mackensen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Common_unit_test_problems&amp;diff=48135</id>
		<title>Common unit test problems</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Common_unit_test_problems&amp;diff=48135"/>
		<updated>2015-06-26T13:25:56Z</updated>

		<summary type="html">&lt;p&gt;Mackensen: /* core_phpunit_advanced_testcase::test_locale_reset */ add centos example&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General Issues ==&lt;br /&gt;
&lt;br /&gt;
=== Segfaults on Oracle ===&lt;br /&gt;
&lt;br /&gt;
When I was running tests on oracle I was getting phpunit sefaulting.. --[[User:Dan Poltawski|Dan Poltawski]] 00:29, 16 May 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; Set statement_cache_size in php.ini: &amp;lt;code&amp;gt;oci8.statement_cache_size = 0&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
(More info: [https://bugs.php.net/bug.php?id=49803 PHP Bug #49803]).&lt;br /&gt;
&lt;br /&gt;
=== Execution ends with &amp;quot;zend_mm_heap corrupted&amp;quot; error ===&lt;br /&gt;
&lt;br /&gt;
This was happening with a standard XAMPP stack, running Moodle against Oracle.&lt;br /&gt;
&lt;br /&gt;
# Verify that you are not using multiple PHP opcode accelerators together (APC, Opcode...). Also try disabling all them (they really don&#039;t help much in a phpunit execution).&lt;br /&gt;
# Set output_buffering in php.ini to 65536 (from default 4096).&lt;br /&gt;
&lt;br /&gt;
=== Many random errors about &amp;quot;Warning: rmdir dataroot/cache/.../.... Directory not empty&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
Use a different $CFG-&amp;gt;phpunit_dataroot , completely apart from your current [LXMW]AMP stack, for example in windows &#039;C:\\Windows\\Temp\\dataroot&#039;. For some reason, unknown at the time of writing this, using any directory within the [LXMW]AMP stack lead to randomly busy/locked (aka, non deletable) files.&lt;br /&gt;
&lt;br /&gt;
== Specific failures ==&lt;br /&gt;
&lt;br /&gt;
=== dml_testcase::test_unique_index_collation_trouble===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Unique index is accent insensitive, this may cause problems for non-ascii languages. This is usually caused by accent insensitive default collation.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; These tests should pass if you use the &amp;lt;code&amp;gt;utf8_bin&amp;lt;/code&amp;gt; collation on your database for unit tests, but we recommend &amp;lt;code&amp;gt;utf8_unicode_ci&amp;lt;/code&amp;gt; for actual live Moodle sites. Work is being done to resolve this issue, read more about the [[Database collation issue]] for further info.&lt;br /&gt;
&lt;br /&gt;
=== dml_testcase::test_sql_binary_equal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SQL operator &amp;quot;=&amp;quot; is expected to be case sensitive Failed asserting that 1 matches expected 2.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; These tests should pass if you use the &amp;lt;code&amp;gt;utf8_bin&amp;lt;/code&amp;gt; collation on your database for unit tests, but we recommend &amp;lt;code&amp;gt;utf8_unicode_ci&amp;lt;/code&amp;gt; for actual live Moodle sites. Work is being done to resolve this issue, read more about the [[Database collation issue]] for further info.&lt;br /&gt;
&lt;br /&gt;
=== grading_manager_testcase::test_tokenize===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;A test using UTF-8 characters has failed. Consider updating PHP and PHP&#039;s PCRE or INTL extensions (MDL-30494) Failed asserting that false is true.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; These tests should pass if you use the &amp;lt;code&amp;gt;utf8_bin&amp;lt;/code&amp;gt; collation on your database for unit tests, but we recommend &amp;lt;code&amp;gt;utf8_unicode_ci&amp;lt;/code&amp;gt; for actual live Moodle sites. Work is being done to resolve this issue, read more about the [[Database collation issue]] for further info.&lt;br /&gt;
&lt;br /&gt;
=== moodlesimplepie_testcase::test_getfeed ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Failed to load the sample RSS file. Please check your proxy settings in Moodle. %s&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; Your moodle needs network connectivity, please check proxy settings.&lt;br /&gt;
&lt;br /&gt;
=== moodlesimplepie_testcase::test_redirect ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Failed asserting that &#039;cURL Error: Operation timed out after 2000 milliseconds with 0 bytes received&#039; is null.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; Your moodle needs network connectivity, please check proxy settings&lt;br /&gt;
&lt;br /&gt;
=== collatorlib_testcase::test_asort_objects_by_method ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Collation aware sorting not supported, PHP extension &amp;quot;intl&amp;quot; is not available.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; Install php intl extension.&lt;br /&gt;
&lt;br /&gt;
Note that, on Windows, this extension does not seem to be included in the installer, but you can get it by downloading the zip, and copying the right DLLs across. If you Google, there are more detailed instructions on Stack Exchange.&lt;br /&gt;
&lt;br /&gt;
===  moodlelib_testcase::test_fix_utf8 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Failed asserting that false is identical to &#039;aaabbb&#039;.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; This problem indicates buggy iconv. See [http://tracker.moodle.org/browse/MDL-33007] for discussion.  So this is a real problem, to be fixed in a future integration cycle&lt;br /&gt;
&lt;br /&gt;
=== filestoragelib_testcase::test_get_file_preview ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Failed asserting that false is an instance of class &amp;quot;stored_file&amp;quot;.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; Unfortunately, the php GD extension is a requirement for this test (see MDL-36447).&lt;br /&gt;
&lt;br /&gt;
Go to your Moodle directory and type &amp;lt;code&amp;gt;php admin/tool/phpunit/cli/util.php --drop&amp;lt;/code&amp;gt;, then reinitialise PHPunit and run the test again.&lt;br /&gt;
&lt;br /&gt;
===core_ddl_testcase::test_row_size_limits===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Row size limit reached in MySQL using InnoDB, configure server to use innodb_file_format=Barracuda and innodb_file_per_table=1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;&amp;quot;Solution&amp;quot;&amp;quot; default InnoDB database tables in MySQL cannot handle more than 10 text columns, so innodb file format should be Barracuda (see MDL-46971)&lt;br /&gt;
&lt;br /&gt;
Running &amp;lt;code&amp;gt;php admin/cli/mysql_compressed_rows.php&amp;lt;/code&amp;gt; will solve the problem.&lt;br /&gt;
&lt;br /&gt;
===  core_phpunit_advanced_testcase::test_locale_reset ===&lt;br /&gt;
&lt;br /&gt;
Failed asserting that two strings are identical. Since 2.9, en_AU.UTF-8 locale is required to run phpunit.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; Install the AU locale on your server if you want to run phpunit. Here are sample commands for installing the en_AU locale:&lt;br /&gt;
&lt;br /&gt;
* Centos:  &amp;quot;sudo localedef -v -c -i en_AU -f UTF-8 en_AU.UTF-8&amp;quot;&lt;br /&gt;
* Ubuntu: &amp;quot;sudo locale-gen en_AU.UTF-8&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== MSSQL failures with core_course_externallib_testcase===&lt;br /&gt;
&lt;br /&gt;
On the MSSQL database driver, some problems occur with  core_course_externallib_testcase, for example:&lt;br /&gt;
&lt;br /&gt;
core_course_externallib_testcase::test_duplicate_course&lt;br /&gt;
&lt;br /&gt;
unserialize(): Error at offset 24191 of 24192 bytes&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; Ensure that the correct configuration is set in freedts.conf (from https://docs.moodle.org/26/en/FreeTDS), e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;text size = 20971520&lt;br /&gt;
client charset = UTF8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== PHP Warning: include_once(PHPUnit/Extensions/Database/Autoload.php): failed to open stream ===&lt;br /&gt;
&lt;br /&gt;
This occurs on Mac installs from experience. The reason this occurs is because DBUnit was not installed during the PHPUnit installation via PEAR.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; In terminal type: &amp;lt;code&amp;gt;sudo pear install -f phpunit/DbUnit&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== !!! Error reading from database !!!!! Unicode data in a Unicode-only collation or ntext data cannot be sent to clients using DB-Library (such as ISQL) or ODBC version 3.7 or earlier. ===&lt;br /&gt;
&lt;br /&gt;
If running unit tests under FreeTDS, remember that without a valid FREETDS environment variable, PHP won&#039;t be able to find the freetds.conf file and will default to version 5.0 which has poor support for unicode collations.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution&#039;&#039;&#039; Ensure a FREETDS environment variable is set prior to running the automated tests, which points to a valid path that contains a freetds.conf file. Also ensure the tds version element is set to a recent enough version (8.0)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution2&#039;&#039;&#039; Under windows you can put the freetds.conf file in the disk root directory where php is being executed (for example C:\freetds.conf). That directory is always looked. Also ensure the tds version element is set to a recent enough version (8.0)&lt;br /&gt;
&lt;br /&gt;
Note: Another potential solution may be to set TDSVER (http://freetds.schemamania.org/userguide/freetdsconf.htm)&lt;br /&gt;
&lt;br /&gt;
[[Category:Unit testing]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Errors running unit tests against Oracle, related with locales, decimal points and friends ===&lt;br /&gt;
&lt;br /&gt;
Surely your PHP CLI (the one executing phpunit) is not aware of the expected Oracle NLS configuration. To enforce it, set at least these 2 env variables in your system (globally or for the current user):&lt;br /&gt;
&lt;br /&gt;
- NLS_LANG to AMERICAN_AMERICA.AL32UTF8&lt;br /&gt;
- NLS_NUMERIC_CHARACTERS to ., (dot &amp;amp; comma)&lt;/div&gt;</summary>
		<author><name>Mackensen</name></author>
	</entry>
</feed>