hoa/test
Hoa\Test is a lightweight PHP testing library from the Hoa project, offering a structured framework for writing and running unit tests. It helps organize assertions and test suites for PHP code and modular Hoa components.
hoa/test is the Hoa project's test runner: a thin layer over atoum that discovers test files under a Test/Unit/ (and Test/Integration/) directory and exposes them through the hoa CLI binary (hoa test:run). It is not a standalone assertion library — everything you assert with (->boolean(), ->string(), ->mock(), ->calling()) comes from atoum underneath.
Minimal steps:
Add it as a dev dependency. Be aware the package is archived (last release 2017), so pin it and pin your PHP version — realistically PHP 7.x only:
composer require --dev hoa/test
This pulls in atoum/atoum, hoa/console, hoa/stream, hoa/consistency and friends.
Add an autoload path for your test namespace so the runner can load suites:
"autoload-dev": { "psr-4": { "Acme\\Greeter\\Test\\": "Test/" } }
Look first at Hoa\Test\Unit\Suite (the base class your suites extend) and then at any real Hoa library's Test/Unit/ folder (e.g. hoa/stream, hoa/console) — those are the canonical, copy-pasteable examples of the expected style.
First use case — a suite in Test/Unit/Greeter.php:
<?php
namespace Acme\Greeter\Test\Unit;
use Hoa\Test;
class Greeter extends Test\Unit\Suite
{
public function case_say_hello()
{
$this
->given($greeter = new \Acme\Greeter())
->when($result = $greeter->sayHello('World'))
->then
->string($result)->isEqualTo('Hello World');
}
}
Run it:
vendor/bin/hoa test:run --directories=Test/Unit
Use vendor/bin/hoa help test:run (or list) to confirm the exact flag names for the version you installed — the options changed across hoa/console releases.
One suite per class under test, mirroring namespaces. The convention is strict: Acme\Greeter\Test\Unit\Greeter lives at Test/Unit/Greeter.php, and each test method is prefixed case_. The runner maps file → class → methods; break the mirroring and you get silent "no tests found" rather than an error.
Follow the given / when / then chain. Hoa suites are atoum suites, so given() / when() / then() are just narrative aliases around the asserter queue. The idiomatic pattern is: build the subject in given, invoke the unit in when, capture the return value as the assignment expression, and assert only in then. Assigning inside when(...) is the house style because it keeps the tested call on one line.
Mocks via atoum's calling(). For collaborators:
$this->given($clock = new \mock\ClockInterface())
->and($this->calling($clock)->now = new \DateTime('2017-01-01'))
->when($result = (new Greeter($clock))->greeting())
->then->string($result)->contains('2017');
Same for $this->mock($class) when you need to assert on call counts afterwards.
Data providers. atoum's @dataProvider annotation on a case_* method keeps working unchanged; use it instead of hand-rolled loops so failures report one case per dataset.
Split unit and integration. Put pure logic in Test/Unit/ and anything touching filesystem, network, or the Hoa\Stream layer in Test/Integration/, then run the two directories as separate CI jobs. Hoa itself does this and it's the main reason the split exists.
CI integration. vendor/bin/hoa test:run exits non-zero on failure, so it drops into Travis/CI as a single line. For a faster local loop, filter to one suite or invoke atoum directly on a single file; the Hoa wrapper adds discovery, not capability.
Composer scripts. Wire it once and let everyone forget the flags:
"scripts": { "test": "hoa test:run --directories=Test/Unit --recursive" }
hoa/consistency, old atoum) are equally stale. Treat it as legacy-only; for greenfield work use PHPUnit or Pest, and only adopt hoa/test if you're already inside the Hoa dependency graph.vendor/bin/hoa (from hoa/console), not hoa/test. If it isn't found, run composer dump-autoload and check vendor/bin.Hoa\Test\Unit\Suite, filename/class name mismatch, methods not prefixed case_, or the Test\ namespace isn't in autoload-dev.hoa test:run wraps atoum's runner, so not every atoum CLI option (--coverage, JUnit output, --loop) is forwarded. Check help test:run before assuming; if you need atoum's full CLI, call vendor/bin/atoum directly against the same Test/Unit directory.case_* method. When assertions give you nothing useful, temporarily replace the chain with a raw var_dump() in when() — the fluent chain hides the intermediate value otherwise.Hoa\Test\Unit\Suite for a project-wide base suite, override atoum's beforeTestMethod / afterTestMethod hooks for fixtures, and register atoum custom asserters if the built-ins don't cover a domain type. That's the intended customization seam — don't fork the runner.Hoa\Test's own surface area is small (base suite, runner command, directory conventions). Reading Hoa\Test\Unit\Suite end-to-end takes five minutes and resolves most "how do I…" questions.How can I help you explore Laravel packages today?