Testing Klyn Applications
The Klyn test framework discovers packaged test classes and executes the complete selection in
one isolated test process and one JIT session. It reports class and method results incrementally
and can persist the complete execution as JSON. The same tests/Start.kn entry point
supports console and graphical runs.
A project needs only one small entry point. Pass
arguments unchanged to TestLauncher.run(); the launcher
handles package filters, console reporting, JSON output, help, and graphical mode. Its return
value is the process exit code.
# tests/Start.kn
import klyn.unittest.launcher
exit(TestLauncher.run(arguments))
Keeping option handling in the framework guarantees that every project exposes the same command line and that new framework options do not require changes to its starter.
All selected classes share one test process and one JIT session. This avoids repeating runtime, compiler, and standard-library initialization for every class while retaining a distinct JIT namespace and a structured result for each source. A fatal native crash can stop the remaining classes; the runner reports every source that could not execute as an infrastructure failure.
The tests directory is the class-loader root. Every test package must therefore
match its directory, exactly as it does for application sources. Discovery is driven by
@TestClass, not by a filename convention; ending test filenames with
Test.kn remains the recommended convention.
tests/
|-- Start.kn
`-- inventory/
|-- InventoryServiceTest.kn
`-- persistence/
`-- InventoryRepositoryTest.kn
# tests/inventory/InventoryServiceTest.kn
package inventory
import klyn.unittest
@TestClass
public class InventoryServiceTest:
@Test
public testAvailableQuantity():
assert 12 - 4 == 8
Declaring package inventory.persistence in
tests/inventory/InventoryServiceTest.kn is an error. Move the file or correct
its package; the runner never hides a package-layout problem.
| Annotation | Execution point |
|---|---|
@TestClass |
Marks the public class containing test methods. |
@BeforeClass |
Runs once before the first test method. |
@Before |
Runs before every test method. |
@Test |
Marks one independently reported test method. |
@After |
Runs after every test method. |
@AfterClass |
Runs once after the last test method. |
package inventory
import klyn.unittest
@TestClass
public class InventoryRepositoryTest:
private _quantity as Int
@BeforeClass
public static prepareDatabase():
print("Preparing test data")
@Before
public resetQuantity():
this._quantity = 10
@Test
public testRemoval():
this._quantity -= 3
assert this._quantity == 7
@After
public verifyInvariant():
assert this._quantity >= 0
@AfterClass
public static closeDatabase():
print("Releasing test data")
Use expected when an exception is the successful outcome of a test. A
@Test(timeout=...) budget limits one test method, while
@TestClass(timeout=...) limits the complete lifecycle of a test class. Both values
are expressed in milliseconds; zero, the default, disables the corresponding limit.
@Test(expected=ValueException)
public testRejectsNegativeQuantity():
throw ValueException("Quantity cannot be negative")
@Test(timeout=500)
public testCompletesQuickly():
value = 40 + 2
assert value == 42
@TestClass(timeout=2000)
public class FastContractTest:
@Test
public completesWithinTheClassBudget():
assert true
A timed-out method is interrupted and reported as failed. It cannot satisfy an
expected declaration. A class budget includes construction,
@BeforeClass, @Before, every @Test,
@After and @AfterClass; source compilation is intentionally excluded.
When method and class budgets are both present, the first deadline reached stops execution.
# Run every @TestClass below tests
klyn tests/Start.kn
# Run one package and all of its subpackages
klyn tests/Start.kn klyn.data
# Combine any number of package roots
klyn tests/Start.kn klyn.data klyn.databases
# Display every supported option
klyn tests/Start.kn --help
Each selected source runs in its own process. A native crash, compilation failure, or leaked
global state in one test class therefore cannot corrupt the next class. Successful entries
and the final successful summary are green; failures are red and identify the affected test
methods. Each class occupies one console line; OK or KO is aligned
against the right edge, and long source names are shortened in the middle without hiding the
test filename.
Running /project/tests/klyn/regex/RegExTest.kn... 0.042 s OK
Test summary: 1/1 test class(es) passed; 8/8 test method(s) passed; 0.042 s.
# Default destination: test-results.json
klyn tests/Start.kn --json
# Explicit destination
klyn tests/Start.kn --json=reports/collections.json klyn.collections
The report records duration, source, package, class and method status, captured standard output and error streams, stack traces, and infrastructure failures. It can be loaded later by the graphical runner.
klyn tests/Start.kn --gui
klyn tests/Start.kn --gui klyn.io klyn.regex
The GUI uses DockWorkspace. Its tree groups packages, classes, and methods and
displays a red or green status dot at the right of each row. The root stays expanded; passing
branches start collapsed, while every branch containing a failure starts expanded. Selecting
a package or class aggregates its details in the central area. The window opens before test
execution starts; tests run in an isolated worker and completed classes are published to the
tree, output, and summary in real time without blocking GUI painting or input.
- Output preserves the complete nominal and error streams.
- Details focuses on the selected package, class, or method.
- File > Save report persists the current report as JSON.
- File > Load report opens a previous JSON execution.
Save and load actions use the embedded SaveFileLightBox and
OpenFileLightBox from klyn.gui.windows.dialogs. They remain inside the
test-runner window and do not start a nested event loop.
Graphical execution is not a separate program. Always use
klyn tests/Start.kn --gui, so discovery, filtering, isolation, and result
semantics remain identical to console mode.
The Klyn extension uses the native VS Code Testing API. Starting a test from the editor, gutter, or Explorer reveals the Tests view and result panel immediately. Packages, classes, and methods remain hierarchical; selecting any node displays the output, duration, and errors aggregated for that node.
Internally, --json-stream publishes framed JSON Lines events whenever a class
starts or completes. This lets IDEs update their test tree in real time while the regular
--json report remains the authoritative final snapshot and fallback.
Build tools can use TestRunner and TestReport directly. Package
filters retain the same exact-or-descendant semantics as the command line.
import klyn.io
import klyn.unittest
runner = TestRunner(FolderPath("tests"))
runner.consoleOutput = false
report = runner.run(["klyn.collections"])
report.save(FilePath("collection-results.json"))
if not report.passed:
Application.exit(Application.EXIT_FAILURE)