Manual:PHP unit testing/Writing unit tests for extensions

The recommended bootstrapping method for extensions is to include your tests in the tests/phpunit/ directory of your extension (alternatively, you can use the UnitTestsList hook). Via either of these methods you can use the MediaWiki core bootstrap support for things like autoloading classes, global functions etc.

Unless your code is truly a standalone library, it's NOT recommended to include a few random MediaWiki core files with custom bootstrapping and attempt to make your tests stand alone.

Register your testsEdit

As of MediaWiki 1.28 (Gerrit change 302944), you no longer need to register your tests with the UnitTestsList hook as long as they are in the tests/phpunit/ directory of your extension - they will automatically be registered.

Let's assume our extension is named Fruits.

  1. Create a hook function for onUnitTestsList.
  2. Register the hook with UnitTestsList.
--- Fruits/Fruits.hooks.php

@@ class FruitsHooks {

  public static function onUnitTestsList( &$paths ) {
    $paths[] = __DIR__ . '/tests/phpunit/';
    return true;

--- Fruits/Fruits.php

// Register hooks
$wgHooks['UnitTestsList'][] = 'FruitsHooks::onUnitTestsList';

Create your testsEdit

Let's say our Fruits extension has a class called AppleFruit.

  1. Create a test file in your extension’s tests/phpunit/ directory, named AppleFruitTest.php
    • Make sure that the file name ends in Test.php or else phpunit will not be able to discover it.
  2. Create a class in that file named AppleFruitTest and extend the MediaWikiTestCase class.
  3. The class must contain a protected function setUp() that calls parent::setUp() as its first task.
  4. The class should contain a protected function tearDown() that calls parent::tearDown() as its last task.
  5. Each of your test functions should :
    • be public.
    • begin their function name with test.
  6. It’s a good idea to add an @group comment to the class. This group name can then be referred to later in order to run tests only in this group or exclude them. You can also place an @group comment above each test function if you wish to further isolate your tests.
 * @group Fruit
 * @covers AppleFruit
class AppleFruitTest extends MediaWikiTestCase {
  private $apple;

  protected function setUp() {
    $this->apple = Fruit::factory( 'apple' );

  protected function tearDown() {
    unset( $this->apple );

  public function testIsEdible() {
    $this->assertTrue( $this->apple->isEdible(), "apples should be edible." );

Run your testsEdit

Single test fileEdit

# from within the core/ directory
tests/phpunit/phpunit.php extensions/Fruits/tests/phpunit/AppleFruitTest.php

If you are using vagrant and get an error message: "Cannot access the database: Unknown database", try adding --wiki wiki to the command line.

All test filesEdit

# from within the core/ directory
tests/phpunit/phpunit.php extensions/Fruits/tests/phpunit/

Create a custom test suiteEdit

core/tests/phpunit/phpunit.php runs with a default test suite defined in core/tests/phpunit/suite.xml. You can alter that test suite by doing the following:

  1. Copy the core/tests/phpunit/suite.xml file to suite.extensions.xml.
  2. Edit the suite.extensions.xml file:
  • remove any unwanted <testsuite> from the <testsuites> node.
  • add or make sure a <testsuite> node exists with the following:
<testsuite name="extensions">
  • Save the file.
  • Run the tests with the custom suite configuration.
    # from within the core/ directory
    tests/phpunit/phpunit.php --configuration tests/phpunit/suite.extensions.xml
  • Tests for any extension loaded in LocalSettings.php will be run. If you want to isolate tests to only your extension, you can exclude groups of tests within the suite.extensions.xml file.

    List groupsEdit

    You can get a list of test groups available for a specific configuration by running:

    tests/phpunit/phpunit.php --configuration tests/phpunit/suite.extensions.xml --list-groups

    Exclude groupsEdit

    You can then exclude specific test groups by adding them to the <groups>, <exclude> node in suite.extensions.xml:


    Tests are considered part of a group when an @group comment is placed above the class or function.

    • __nogroup__ covers any test that has not been given an @group comment.
    • phpunit also considers an @author comment as an @group comment, but @group is preferred.

    Add your tests to JenkinsEdit

    MediaWiki maintains a Jenkins server that automates the software building process. This includes automatically running MediaWiki tests as software is committed to the MediaWiki code repository. If your extension exists in that repo, you can add your extension’s test to the Jenkins build process.

    1. Clone the integration/config repo and create a new git branch.

    # replace <your-user-name>
    git clone ssh://<your-user-name>
    cd config
    git checkout -b add-fruits-tests

    2. Open the jjb/mediawiki-extensions.yaml file in the project
    3. Locate the - project: name: mwext section
    4. Find your extension under the ext-name: section or add it

    # use only spaces, no tabs
    # exact spacing is very important
    - project:
        name: mwext
        # By default we do not need any other extensions:
        dependencies: ""
         - FormatDates
         - FormatNum
         - FormelApplet
         - FormPreloadPostCache
         - Foxway
         - Fruits    # your extension already present or just added

    5. Commit the changes

    git commit --all

    6. Submit the changes to gerrit for code review

    git pull --rebase origin master
    git review --no-rebase

    7. Once the change has been merged, your extension’s tests will automatically run when you commit changes to the MediaWiki code repo.

    Extension dependenciesEdit

    If your extension requires other extensions to be present in order to work properly, add them as dependencies:

    # note the colon at the end of the line
    # note the additional two space indentation on the dependency line
    # required extensions are comma delimited
         - Fruits:
            dependencies: 'SyntaxHighlight_GeSHi,Scribunto,TemplateData'