Manual:PHP unit testing/Writing unit tests for extensions

From mediawiki.org
Jump to navigation Jump to search
MediaWiki Flower
« Unit testing
PHPUnit testing

The recommended bootstrapping method for extensions is to create your tests in the tests/phpunit/ directory of your extension (or use the UnitTestsList hook). Either of these methods will ensure MediaWiki core is bootstrapped for things like autoloading classes, global functions etc.

Two types of tests[edit]

MediaWiki supports "unit" tests and "integration" tests. The general idea is that with "unit" tests, you create mocks of all the objects that are used by methods you are testing. With integration tests, you have access to actual objects generated by other code, including data loaded from the database. If you are writing unit tests, extend MediaWikiUnitTestCase and place your tests in tests/phpunit/unit. If you are writing integration tests, extend MediaWikiIntegrationTestCase and place your tests in tests/phpunit/integration.

Create your tests[edit]

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. If you need to perform an operation on teardown of the test, the class may 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.
    • There are two special group names: "Database" and "Standalone":
      1. Tests tagged into the group Database are allowed to access the wiki's database and make destructive changes to the wiki; suites from extensions which are tagged this way are tested by Continuous Integration separately, in isolation from each other. Other tests are forbidden from making changes to the wiki, and will fail.
      2. Tests tagged into the group Standalone are only run for patches to that repo, and not for other repos which depend on this one. This lets you write extensive, expensive tests for features your extension provides, without slowing down the test runs for other repos. You must get CI configured for your repo to run these tests; by default, the stand-alone test suite isn't run.
<?php
/**
 * @group Fruit
 * @covers AppleFruit
 */
class AppleFruitTest extends MediaWikiUnitTestCase {
  private $apple;

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

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

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

For integration tests that involve global state, MediaWikiServices, etc, extend MediaWikiIntegrationTestCase instead (formerly known as MediaWikiTestCase).

Run your tests[edit]

Single test file[edit]

# 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 files[edit]

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

Create a custom test suite[edit]

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">
      <file>/full/path/to/core/tests/phpunit/suites/ExtensionsTestSuite.php</file>
      <file>/full/path/to/core/tests/phpunit/suites/ExtensionsParserTestSuite.php</file>
    </testsuite>
    
  3. Save the file.
  4. 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 groups[edit]

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 groups[edit]

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

<groups>
  <exclude>
    <group>Utility</group>
    <group>Broken</group>
    <group>ParserFuzz</group>
    <group>Stub</group>
    <group>Database</group>
    <group>ParserTests</group>
    <group>ParserTests_LuaParserTests</group>
    <group>__nogroup__</group>
    <group>large</group>
    <group>medium</group>
  </exclude>
</groups>

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 Jenkins[edit]

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>@gerrit.wikimedia.org:29418/integration/config.git
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: ""

    ext-name:
     - 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 dependencies[edit]

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'