Test Runners
What it is
Section titled “What it is”A test runner discovers test files, executes the cases, collects results and reports pass/fail. It is the engine underneath the assertions: it decides what runs, in what order, how failures are surfaced, and how exit codes drive CI.
Runners split into two broad styles:
Code-driven runners Keyword/table-driven runners ┌───────────────────────┐ ┌───────────────────────────┐ │ test files → functions│ │ keyword libraries │ │ ↓ run in-process │ │ ↓ data tables .robot │ │ assertions + fixtures │ │ steps read like prose │ └──────────┬────────────┘ └────────────┬──────────────┘ ▼ ▼ exit code → CI exit code + HTML report → CIRobot Framework is the flagship of the second style: tests are written as
human-readable keywords in tabular .robot files, so testers and domain experts
can read and author suites without programming. It is widely used for system and
acceptance testing and ships its own runner command, robot.
When to use it / when to avoid it
Section titled “When to use it / when to avoid it”Use a runner when
- You need consistent discovery, isolation and reporting for a suite of tests
- You want a single exit code that gates your CI pipeline
- You need parallelism, retries, tagging or sharding at scale
- Non-programmers must read or write the tests (→ Robot Framework, keyword-driven)
Avoid or reduce it when
- The project has a handful of one-off checks you run by hand
- The runner would become a thick framework layer over simple scripts
- You only need a quick assertion and already have a shell/script workflow
Frameworks & tools
Section titled “Frameworks & tools”| Tool | Ecosystem | Notes |
|---|---|---|
| Vitest | JS/TS | Vite-native, Jest-compatible API, fast watch mode |
| Jest | JS/TS | Batteries included: runner, assertions, mocks, coverage |
| Mocha | JS/TS | Flexible runner; pair with Chai/Sinon |
| pytest | Python | Fixtures, parametrisation, rich plugin ecosystem |
| go test | Go | Built in; table-driven tests are idiomatic |
| JUnit 5 | Java/JVM | The JVM standard, with a platform/engine split |
| TestNG | Java/JVM | Suites, groups, parallel and data-driven execution |
| xUnit | .NET | Modern, [Fact]/[Theory] |
| NUnit | .NET | Mature, data-driven [TestCase] |
| Robot Framework | Python/JVM | Keyword-driven runner; tabular .robot suites, robot CLI |
Quick setup
Section titled “Quick setup”npm install -D vitestnpx vitest # watch mode; `npx vitest run` for CIpip install pytestpytest -qgo test ./...go test -run TestCheckout ./...# Via Maven Surefiremvn -q testdotnet new xunit -o MyApp.Testsdotnet testExample
Section titled “Example”import { describe, it, expect } from 'vitest';
describe('parser', () => { it('reads a key=value line', () => { expect(parse('a=1')).toEqual({ a: '1' }); });});def test_reads_key_value(): assert parse('a=1') == {'a': '1'}func TestParse(t *testing.T) { if got := Parse("a=1"); got["a"] != "1" { t.Fatalf("got %v", got) }}import static org.junit.jupiter.api.Assertions.assertEquals;import org.junit.jupiter.api.Test;
class ParserTest { @Test void readsKeyValue() { assertEquals("1", Parser.parse("a=1").get("a")); }}using Xunit;
public class ParserTests{ [Fact] public void ReadsKeyValue() { Assert.Equal("1", Parser.Parse("a=1")["a"]); }}*** Settings ***Library Collections
*** Test Cases ***Reads Key Value ${result}= Parse a=1 Should Be Equal ${result}[a] 1Anti-patterns & best practices
Section titled “Anti-patterns & best practices”- Keep the runner thin. A runner should orchestrate, not contain business setup; push reusable logic into libraries and fixtures.
- Pin the runner and its plugins so a CI upgrade does not change behaviour silently.
- Fail fast, but report everything. Use
--bailonly when flakiness is under control. - Use tags/groups for selective runs instead of commenting tests in and out.
- For keyword-driven suites, keep keywords reusable and avoid putting assertion logic in ad-hoc strings scattered across test cases.
- Do not mix styles in one suite without reason: pick code-driven or keyword-driven per layer of the pyramid.
Self-assessment quiz
Section titled “Self-assessment quiz”Self-assessment quiz
Pick one answer per question, then press Check answers.