# 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/unitsrc
```
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