Index
# Testing Tests run under PHPUnit, from the folder of the project or the library they belong to. **Done means `phpunit` passes.** ```sh cd libs/weather && phpunit # a library's own suite phpunit # an application's, from its root php tools/mmo.php verify --lib=weather # from the hub: lint + phpstan + tests on what changed ``` ## `phpunit.xml` At the root, beside `mmo.json` (which names it under its `tests` key). ```xml tests/unit src ``` Two things there are easy to get wrong: - **the suite points at `tests/unit`, not at `tests/`.** The house convention names a test class `TestThing`, not `ThingTest`, so the suite cannot filter on a `Test` suffix — it matches `*.php` instead. Pointed at `tests/` itself, it would collect `tests/bootstrap.php` and every helper beside it as a test. - **`beStrictAboutOutputDuringTests`** is on, so anything printed during a test fails it. @see below. ## `tests/bootstrap.php` It boots the application for the suite: the mode, the framework's own `TestCase`, and somewhere for the log to go. ```php fragment namespace AcmePortal\tests; define('MMO_MODE', 'dev'); define('MMO_DEBUG', 'error+'); //in dev mode the framework also mirrors warnings to STDERR, which phpunit attributes to nothing in particular define('MMO_DEBUG_STDERR', 0); require(dirname(__DIR__) . '/bootstrap.php'); //the base class of the framework's own tests require(dirname(__DIR__) . '/libs/core/tests/TestCase.php'); //phpunit is strict about output during tests, and the logger writes to stdout by default. NOT to null, which //makes the Application hold every log until shutdown and then print the lot. \MMO\app()->setStream(sys_get_temp_dir() . '/acme.portal-tests.log'); ``` The `setStream()` line is the one people miss: without it the logger writes to stdout and `beStrictAboutOutputDuringTests` fails tests that were otherwise fine. Sending it to null is worse — the Application then holds every log until shutdown and prints the lot at the end. ## A test `tests/unit/TestArticle.php` — named `TestArticle`, not `ArticleTest`: ```php fragment namespace AcmePortal\tests\unit; use AcmePortal\tests\TestCase; class TestArticle extends TestCase { public function testItValidatesItsName(): void { $article = new \AcmePortal\entities\Article(['name' => '']); $this->assertFalse($article->isValid()); } } ``` Most of the framework needs no server and no database to exercise: `require 'bootstrap.php';` and use the class directly. `php tools/mmo.php make test --lib=` writes a first test for an existing class, and `make entity` and `make controller` each write one along with the class. @see NewLibrary.md