Test conventions (plan 10-workflow-example.md, section 6.3)
Integration tests only. Every test exercises a URL end to end through real HTTP handling, routing, middleware, views, and services. Isolated unit tests are forbidden.
Placement
Test file path and name derive from the URL under test; exactly one structured place per route:
| Route | Test file |
|---|---|
/health |
tests/example/health_test.cpp |
/users/:id |
tests/example/users/id_test.cpp |
/orm/users |
tests/example/orm/users_test.cpp |
Shared helpers live in tests/example/support/ and are not tests.
Case template
Every test file follows Arrange / Act / Assert:
// Route: GET /orm/users (one-line behavior note)
#include "support/Assert.hpp"
using namespace molo::example::test;
int main() {
Fixture f; // Arrange: seed via app API
auto res = f.client->get("/orm/users"); // Act: one HTTP request
check(res.status == 200, "status 200"); // Assert: status ...
check(contains(res.body, "\"rows\""), "body shape");
check(!f.services.sqlite->tables().empty(), "side effect: table exists");
return finish("orm/users"); // names the route, never silent
}
Every route needs at minimum: happy path, auth failure (or 404/405 when the route has no auth), validation failure, and one limit case (body too large, rate limited, or not found).
Rules
- Seed through the app API, never direct service writes, unless the test targets self-healing.
- Assert status code, content-type, body shape, plus one side-effect check (DB row, metric emitted, listener ran, file listed).
- Loud skips: if a fixture or the environment cannot be verified, fail with a clear reason and counter. Never silently pass.
- Fixture services reset per test binary (fresh
Fixtureper main); never share state across files. - Caps: full suite max 10 min; single test max 30 s. Zero tolerance for flakes: quarantine plus spec gap entry, fix within one session.
Running
make -f example/example.mk example-test # this part, standalone
make test # whole repo (root Makefile)
Each binary prints ok: lines and ends with PASS: <route> or
FAIL: <route> (N failures) with a nonzero exit.