Tests
ORM::Factory ships a parallel t/ and specs/ tree. Both contain the same
coverage; t/ is the canonical prove6 suite (kept while ecosystem tooling
still expects it), and specs/ is the BDD-style suite run by
behave. Long-term the t/ tree
will be retired in favour of specs/.
Running the suite
./test.raku runs the whole suite (the prove6 t/ tests, then the behave
specs/) once, against the adapter named in config/application.json (the
test environment's primary connection). It provisions the schema first
(createdb → reset → migrate), probes the database, and skips with a
message describing how to enable it if it is unreachable. With DATABASE_URL
set it runs against that adapter instead (this is what CI does per matrix
entry).
1 | |
./test-all.raku runs the suite once per adapter by copying each
config/application.json-*-example over config/application.json in turn,
backing up and restoring your own config around the run. This is the single
command that exercises PostgreSQL, MySQL, and SQLite together.
1 | |
To narrow a single test.raku run to a subset of adapters, pass --adapter:
1 2 | |
The behave specs run with --parallel=N, where N is the test environment's
parallel count. behave's default mode runs one subprocess per spec file, up
to N in flight, each on its own per-worker database. Shared test doubles live
in specs/lib/Factory/Test/Models.rakumod (declared once and imported) rather
than inline in each spec. behave's example-discovery pass loads every spec into
one parent process, so a double declared inline in several specs would redeclare
across files; keeping them in one module avoids that.
Running with prove6 or behave directly
To run the prove6 suite once against your default adapter:
1 | |
To run a single behave spec file:
1 | |
Layout convention: t/ ↔ specs/ mirroring
Every test file in t/ has a corresponding spec in specs/ and vice versa.
Shared code (helpers, sample data, parsers reused by both) lives in
specs/lib/ and is added to the path by test.raku. The mirroring is a hard
rule, not an aspiration:
- a new behaviour gets one
t/.../*.rakutestand onespecs/.../*-spec.raku; - shared scaffolding (model classes, parse helpers) goes in
specs/lib/Factory/Test/...; - the spec/test runner (
test.raku) treats both trees as first-class.
Layout convention: db/ vs unit pass
Inside both trees, a test or spec that needs a live database lives under the
tree's top-level db/ (t/db/**, specs/db/**) and is run once per
reachable adapter with DATABASE_URL set and migrations applied. Everything
else is DB-agnostic and runs once in the "unit" pass with no database.
The marker is the leading path segment. specs/db/connection-spec.raku is
DB-backed; a db folder nested deeper (specs/model/db/...) is not.
Configuring the database
./test.raku picks a URL per adapter from, in order:
DATABASE_URL(if set, that single URL is used and no probing is done);FACTORY_PG_URL,FACTORY_MYSQL_URL,FACTORY_SQLITE_URL(per-adapter overrides);config/application.json(thetestenvironment's primary connection supplies the database name, combined with per-adapter defaults);- a built-in default per adapter (PostgreSQL at
localhost:5432, MySQL at127.0.0.1:3306, SQLite in:memory:).
The SQLite suite always runs in memory.
config/application.json uses the per-environment named-connection shape that
ORM::ActiveRecord reads:
1 2 3 4 5 6 7 8 9 | |
The test environment's parallel key sets how many behave worker slots the
DB-backed specs run across, and therefore how many per-worker databases get
provisioned. Copy one of the config/application.json-*-example files to
config/application.json to start.
Per-test factory-registry reset
The factory registry is process-global mutable state. To prevent tests leaking definitions into each other, reset it before each example.
In a behave spec:
1 2 3 4 5 6 7 8 9 10 11 12 | |
In a prove6 test, call ORM::Factory.reload at the top of each test block:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
behave runs each spec file in its own process, so cross-file leakage isn't
possible by construction; only within-file isolation requires the manual
reload. prove6 runs every t/ file in a single harness process, so the
same reload discipline applies there.
Migration runner
bin/factory drives
ORM::ActiveRecord's schema
tooling over db/migrate/ to set up the test schema. It is a no-op (exit 0)
when there are no migration files, so the script is safe to invoke
unconditionally from test.raku.
1 2 3 | |
The DB-backed specs run under behave with --parallel=N, where N is the
test environment's parallel count. behave suffixes each worker slot's
database (factory_test_0, factory_test_1, …), so test.raku provisions
those per-worker databases by passing --parallel to createdb, migrate,
and check. The t/ (prove6) tests run against the base, unsuffixed database.
When db/migrate/ is non-empty, the runner requires ORM::ActiveRecord to
be installed (it is a test-depends of ORM::Factory).