Date: 2026-07-06
Testing should be part of the language surface, not an afterthought hidden in a separate framework.
Hum should support two related forms:
tests:
empty title is rejected
saved task can be shown
and:
test add task rejects empty title {
does:
expect add task("") fails with TaskError.empty_title
}
tests: is an obligation. test is executable evidence.
A senior engineer reads requirements and immediately hears test cases:
- precondition should reject invalid input
- postcondition should be checked after success
- edge case should get a regression test
- security promise should get an adversarial test
- cost claim should get a benchmark or static cost check
Hum should make that translation visible.
Hum should eventually support:
- unit tests
- integration tests
- property tests
- fuzz tests
- regression tests
- model tests
- contract-generated tests
- benchmark tests through
benchmarks:
Benchmarks are related, but separate. A test checks behavior. A benchmark checks measured performance.
A test is a top-level form.
test add task rejects empty title {
why:
empty tasks should never be saved
uses:
fake tasks
covers:
add task
TaskError.empty_title
does:
expect add task("") fails with TaskError.empty_title
}
Tests may use the same intent blocks as tasks where useful:
why:explains the test's purposeuses:names fixtures or capabilitieschanges:names test state that may changecovers:names tasks, branches, contracts, or risksneeds:declares generated input assumptionswatch for:records tricky test hazardscost:prevents tests from becoming accidentally expensivedoes:contains executable expectations
Property tests should be first-class because they match Hum's contract style.
test add task saves any nonempty title(title: Text) property {
needs:
title is not empty
title is not only spaces
covers:
add task ensures new task is saved
add task ensures new task is not done
does:
let result = add task(title)
expect result is ok
expect tasks contains task with title
}
Fuzz tests should come naturally from watch for: and protects:.
test fuzz task titles(title bytes: Bytes) fuzz {
why:
title input may contain unusual bytes or whitespace
covers:
add task watch for title may be only spaces
does:
let title = decode text title bytes or ""
call add task(title)
expect no panic
}
Regression tests should not get their own top-level keyword.
Use the same test form with a regression kind:
test empty title with spaces is rejected regression {
why:
prevent blank-looking tasks from being saved again
regression:
found when title " " was accepted as nonempty
covers:
add task watch for title may be only spaces
TaskError.empty_title
does:
expect add task(" ") fails with TaskError.empty_title
}
Why not a separate regression top-level form?
- It adds another concept for beginners.
- It duplicates
testbehavior. - It makes tooling branch around syntax instead of metadata.
- It weakens the simple rule: behavior evidence is always
test.
Regression tests should still be first-class in tooling:
hum test --kind regression
hum test --changed-contracts
hum test --stale
A regression test should usually include a regression: block that records the
bug, incident, issue, or failure mode it prevents.
Hum should generate test skeletons from:
needs:invalid casesensures:success checksfails when:error caseswatch for:edge casesprotects:adversarial casescost:static cost checksbenchmarks:measured performance checks
Generated tests should be visible source or generated artifacts, not invisible magic.
Test failures should preserve blame:
error[HUM-TEST-004]: expected `add task("")` to fail with `TaskError.empty_title`
blame:
test add task rejects empty title
related contract:
add task fails when title is empty
The test runner should link failures back to contract blocks.
Do not let tests: become a checkbox list that nobody runs.
If a task declares tests:, Hum tooling should show whether each obligation is:
missing
generated
implemented
passing
failing
stale
A stale test is one whose covered contract changed since the test was written.
Milestone 0 should parse top-level test blocks, emit them into the semantic
graph, and print generated Hum test skeletons for obligations that do not yet
have exact covers: links. It does not need to run them yet.
Milestone 1 can execute basic tests against the interpreter or tiny executable core.