Skip to content
Snippets Groups Projects
phpunit.md 7.51 KiB
Newer Older
  • Learn to ignore specific revisions
  • mickadoo's avatar
    mickadoo committed
    
    
        The test suites require a small amount of [setup](/testing/index.md#setup).  If your system was created via [buildkit](/tools/buildkit.md) and
        [civibuild](/tools/civibuild.md), then it was handled automatically.
    
    mickadoo's avatar
    mickadoo committed
    
    
    [PHPUnit](https://phpunit.de/) tests ensure that CiviCRM's PHP logic is working as expected — for example,
    ensuring that the `Contact.create` API actually creates a contact.
    
    mickadoo's avatar
    mickadoo committed
    
    
    ## Binary
    
    PHPUnit provides a command-line tool.  In [buildkit](/tools/buildkit.md), this tool is named `phpunit4`.  In other environments, it might be
    `phpunit` or `phpunit.phar`.
    
    PHPUnit tests are grouped together into *suites*.  For example, the `CRM` suite includes the tests `CRM_Core_RegionTest`,
    
    totten's avatar
    totten committed
    `CRM_Import_Datasource_CsvTest`, and many others.
    
    Each suite has its own coding conventions.  For example, all tests in the `CRM` suite extend the base class `CiviUnitTestCase` and execute on the
    headless database. They require a special environment variable (`CIVICRM_UF`).
    
    You'll find suites in many places, such as `civicrm-core`, `civicrm-drupal`, and various extensions. In `civicrm-core`, the main suites are:
    
    | Suite   | Type | CMS | Typical Base Class | Comment |
    | ------- | ---- | --- | ------------------ | ----------- |
    
    |`api_v3` | [Headless](/testing/index.md#headless) |Agnostic|`CiviUnitTestCase`|Requires `CIVICRM_UF=UnitTests`|
    |`Civi`   | [Headless](/testing/index.md#headless) |Agnostic|`CiviUnitTestCase`|Requires `CIVICRM_UF=UnitTests`|
    |`CRM`    | [Headless](/testing/index.md#headless) |Agnostic|`CiviUnitTestCase`|Requires `CIVICRM_UF=UnitTests`|
    |`E2E`    | [E2E](/testing/index.md#e2e) |Agnostic|`CiviEndToEndTestCase`|Useful for command-line scripts and web-services|
    |`WebTest`| [E2E](/testing/index.md#e2e) |Drupal-only|`CiviSeleniumTestCase`|Useful for tests which require a full web-browser|
    
    To run any PHPUnit test, use a command like this:
    
    mickadoo's avatar
    mickadoo committed
    
    ```bash
    
    $ cd /path/to/my/project
    $ phpunit4 ./tests/MyTest.php
    
    mickadoo's avatar
    mickadoo committed
    ```
    
    totten's avatar
    totten committed
    Note how the command involves a few elements, such as the base-path of the project, the name of the PHPUnit binary, and the relative path of the test.
    
    Let's apply this to a more realistic example.  Suppose we used `civibuild` to create a Drupal 7 site with a copy of `civicrm-core` in the typical
    
    totten's avatar
    totten committed
    folder, `sites/all/modules/civicrm`.  To run a typical test file like `tests/phpunit/CRM/Core/RegionTest.php`, you might execute:
    
    $ cd ~/buildkit/build/dmaster/sites/all/modules/civicrm
    $ phpunit4 ./tests/phpunit/CRM/Core/RegionTest.php
    ```
    
    
    This command ought to work.  It's well-formed.  It *would* work in many cases -- but here it produces an error:
    
    
    ```
    PHPUnit 4.8.21 by Sebastian Bergmann and contributors.
    
    EEEEEEEEE
    
    Time: 450 ms, Memory: 17.75Mb
    
    There were 9 errors:
    
    1) CRM_Core_RegionTest
    exception 'RuntimeException' with message '_populateDB requires CIVICRM_UF=UnitTests'...
    
    mattwire's avatar
    mattwire committed
    ```
    
    What's going on?  The `CRM` suite (and its siblings, `api_v3` and `Civi`) has a special requirement: set the environment variable `CIVICRM_UF`.  This
    revised command should correct the issue:
    
    ```bash
    $ cd ~/buildkit/build/dmaster/sites/all/modules/civicrm
    $ env CIVICRM_UF=UnitTests phpunit4 ./tests/phpunit/CRM/Core/RegionTest.php
    ```
    
    !!! tip "Using PhpStorm for local debugging"
    
    
        PhpStorm is an IDE which provides built-in support for executing tests with a debugger -- you can set breakpoints and inspect variables while the tests run.
    
        Once you've successfully run a test on the command-line, you can take it to the next level and [run the tests within PhpStorm](/tools/phpstorm.md#testing).
    
    
    !!! tip "Using `civi-test-run` for continuous integration"
    
        In continuous-integration, one frequently executes a large number of tests from many suites.  [civi-test-run](/tools/civi-test-run.md) is a
        grand unified wrapper which runs *all* CiviCRM test suites, and it is more convenient for use in CI scripts.
    
    !!! tip "Using the legacy wrapper"
    
        Up through CiviCRM v4.6, the CiviCRM repository included a custom, forked version of PHPUnit. One would execute this command as:
    
        ```bash
        $ cd /path/to/civicrm
        $ cd tools
        $ ./scripts/phpunit CRM_Core_RegionTest
        ```
    
        As of v4.7+, there is no longer a fork, and you can use standard PHPUnit binaries. For backward compatibility,
        v4.7+ still includes a thin wrapper script (`tools/scripts/phpunit`) which supports the old calling convention.
    
    !!! tip "Selecting tests with `AllTests.php`"
    
    
        In `civicrm-core`, there are several suites (`CRM`, `api_v3_`, etc). Each suite has a file named `AllTests.php` which can be used as follows:
    
        ```bash
        $ cd /path/to/civicrm
        $ env CIVICRM_UF=UnitTests phpunit4 ./tests/phpunit/CRM/AllTests.php
        ```
    
    
    !!! tip "Selecting tests with `--filter`, `--group`, etc"
    
    
        The PHPUnit CLI supports a number of [filtering options](https://phpunit.de/manual/current/en/textui.html). For example,
        execute a single test function, you can pass `--filter`, as in:
    
        ```bash
        $ env CIVICRM_UF=UnitTests phpunit4 ./tests/phpunit/CRM/Core/RegionTest.php --filter testOverride
        ```
    
    
    !!! tip "Selecting tests with PHPUNIT_TESTS"
    
    
        If you want to hand-pick a mix of tests to execute, set the environment variable `PHPUNIT_TESTS`.  This a space-delimited list of classes and
        functions. For example:
    
        ```bash
        $ env PHPUNIT_TESTS="MyFirstTest::testFoo MySecondTest" CIVICRM_UF=UnitTests phpunit4 ./tests/phpunit/EnvTests.php
        ```
    
    When writing headless tests for `civicrm-core`, extend the class `\CiviUnitTestCase`.
    
    mattwire's avatar
    mattwire committed
    
    But for extensions you should extend directly from `\PHPUnit_Framework_TestCase`.
    
    !!! note
        Once we move to a PHP5.4 minimum requirement we can break up CiviUnitTestCase.php into `traits` so the helper functions are more accessible to extensions.  Currently you have to copy them into your extensions test environment (eg. `callAPISuccess`).
    
    mickadoo's avatar
    mickadoo committed
    
    Test methods naming should follow the pattern:
    
    - Start with test
    - The name should describe what the test does, e.g. testCreateWithWrongParamsType
    
    
    Sean Madsen's avatar
    Sean Madsen committed
    It is also recommended that your tests implement `HeadlessInterface` to run your
    test against a fake, headless database. `CiviTestListener` will automatically
    
    mickadoo's avatar
    mickadoo committed
    boot Civi. These tests do not use a real CMS and are faster.
    
    Alternatively, if you wish to run a test in a live (CMS-enabled) environment,
    implement `EndToEndInterface`.
    
    The `\Civi\Test` class offers a range of methods for setting up your test and
    installing extensions. Read [the documentation here][civi-test-class] for more
    information.
    
    ### Test Data
    
    It's important that each test is responsible for setting up the data it requires
    and returning the database to the original state after it is complete. To help
    with that there are two methods:
    
    - `setUp` is executed before each test method
    - `tearDown` is executed after each test method
    
    
    Sean Madsen's avatar
    Sean Madsen committed
    Sometimes it will be convenient to prepare test data for whole test case -
    
    mickadoo's avatar
    mickadoo committed
    in such case, you will want to put all the test data creation code in there.
    
    
    Another option is for your test to implement `TransactionalInterface`.  That
    will guarantee that each test will be wrapped in a SQL transaction which
    automatically rolls back any database changes.
    
    mickadoo's avatar
    mickadoo committed
    
    !!! warning
    
    Sean Madsen's avatar
    Sean Madsen committed
        Schema changes in your test will cause an auto-commit of all changes, and
    
    Sean Madsen's avatar
    Sean Madsen committed
        therefore the transaction will be ignored. This includes `TRUNCATE TABLE`,
    
        because this implicitly drops and re-creates the table. If your tests create
        custom tables or change the database schema please be aware you may need to
        manually reset it.
    
    mickadoo's avatar
    mickadoo committed
    
    [civi-test-class]: https://github.com/civicrm/org.civicrm.testapalooza/blob/master/civi-test.md