Changeset View
Changeset View
Standalone View
Standalone View
src/docs/contributor/unit_tests.diviner
@title Writing Unit Tests | @title Writing Unit Tests | ||||
@group developer | @group developer | ||||
Simple guide to Arcanist and Phabricator unit tests. | Simple guide to Arcanist and Phorge unit tests. | ||||
= Overview = | = Overview = | ||||
Arcanist and Phabricator provide and use a simple unit test framework. This | Arcanist and Phorge provide and use a simple unit test framework. This | ||||
document is aimed at project contributors and describes how to use it to add | document is aimed at project contributors and describes how to use it to add | ||||
and run tests in these projects or other libphutil libraries. | and run tests in these projects or other libphutil libraries. | ||||
In the general case, you can integrate `arc` with a custom unit test engine | In the general case, you can integrate `arc` with a custom unit test engine | ||||
(like PHPUnit or any other unit testing library) to run tests in other projects. | (like PHPUnit or any other unit testing library) to run tests in other projects. | ||||
See @{article:Arcanist User Guide: Customizing Lint, Unit Tests and Workflows} | See @{article:Arcanist User Guide: Customizing Lint, Unit Tests and Workflows} | ||||
for information on customizing engines. | for information on customizing engines. | ||||
= Adding Tests = | = Adding Tests = | ||||
To add new tests to a Arcanist or Phabricator module: | To add new tests to a Arcanist or Phorge module: | ||||
- Create a `__tests__/` directory in the module if it doesn't exist yet. | - Create a `__tests__/` directory in the module if it doesn't exist yet. | ||||
- Add classes to the `__tests__/` directory which extend from | - Add classes to the `__tests__/` directory which extend from | ||||
@{class:PhabricatorTestCase} (in Phabricator) or | @{class:PhabricatorTestCase} (in Phorge) or | ||||
@{class@arcanist:PhutilTestCase} (elsewhere). | @{class@arcanist:PhutilTestCase} (elsewhere). | ||||
- Run `arc liberate` on the library root so your classes are loadable. | - Run `arc liberate` on the library root so your classes are loadable. | ||||
= Running Tests = | = Running Tests = | ||||
Once you've added test classes, you can run them with: | Once you've added test classes, you can run them with: | ||||
- `arc unit path/to/module/`, to explicitly run module tests. | - `arc unit path/to/module/`, to explicitly run module tests. | ||||
- `arc unit`, to run tests for all modules affected by changes in the | - `arc unit`, to run tests for all modules affected by changes in the | ||||
working copy. | working copy. | ||||
- `arc diff` will also run `arc unit` for you. | - `arc diff` will also run `arc unit` for you. | ||||
= Example Test Case = | = Example Test Case = | ||||
Here's a simple example test: | Here's a simple example test: | ||||
lang=php | lang=php | ||||
class PhabricatorTrivialTestCase extends PhabricatorTestCase { | class PhorgeTrivialTestCase extends PhabricatorTestCase { | ||||
private $two; | private $two; | ||||
public function willRunOneTest($test_name) { | public function willRunOneTest($test_name) { | ||||
// You can execute setup steps which will run before each test in this | // You can execute setup steps which will run before each test in this | ||||
// method. | // method. | ||||
$this->two = 2; | $this->two = 2; | ||||
} | } | ||||
public function testAllIsRightWithTheWorld() { | public function testAllIsRightWithTheWorld() { | ||||
$this->assertEqual(4, $this->two + $this->two, '2 + 2 = 4'); | $this->assertEqual(4, $this->two + $this->two, '2 + 2 = 4'); | ||||
} | } | ||||
} | } | ||||
You can see this class at @{class:PhabricatorTrivialTestCase} and run it with: | You can see this class at @{class:PhabricatorTrivialTestCase} and run it with: | ||||
phabricator/ $ arc unit src/infrastructure/testing/testcase/ | phorge/ $ arc unit src/infrastructure/testing/testcase/ | ||||
PASS <1ms* testAllIsRightWithTheWorld | PASS <1ms* testAllIsRightWithTheWorld | ||||
For more information on writing tests, see | For more information on writing tests, see | ||||
@{class@arcanist:PhutilTestCase} and @{class:PhabricatorTestCase}. | @{class@arcanist:PhutilTestCase} and @{class:PhabricatorTestCase}. | ||||
= Database Isolation = | = Database Isolation = | ||||
By default, Phabricator isolates unit tests from the database. It makes a crude | By default, Phorge isolates unit tests from the database. It makes a crude | ||||
effort to simulate some side effects (principally, ID assignment on insert), but | effort to simulate some side effects (principally, ID assignment on insert), but | ||||
any queries which read data will fail to select any rows and throw an exception | any queries which read data will fail to select any rows and throw an exception | ||||
about isolation. In general, isolation is good, but this can make certain types | about isolation. In general, isolation is good, but this can make certain types | ||||
of tests difficult to write. When you encounter issues, you can deal with them | of tests difficult to write. When you encounter issues, you can deal with them | ||||
in a number of ways. From best to worst: | in a number of ways. From best to worst: | ||||
- Encounter no issues; your tests are fast and isolated. | - Encounter no issues; your tests are fast and isolated. | ||||
- Add more simulated side effects if you encounter minor issues and simulation | - Add more simulated side effects if you encounter minor issues and simulation | ||||
Show All 11 Lines |
Content licensed under Creative Commons Attribution-ShareAlike 4.0 (CC-BY-SA) unless otherwise noted; code licensed under Apache 2.0 or other open source licenses. · CC BY-SA 4.0 · Apache 2.0