test - Test discovery / runner #
The test module provides a testing framework for Quest with assertions, test organization, and reporting.
Test Definition #
test.describe(name, fn) #
Define a test suite/group
Parameters:
name- Suite name (Str)fn- Function containing tests
Example:
test.describe("String operations", fun ()
test.it("concatenates strings", fun ()
test.assert_eq("hello" + " world", "hello world")
end)
test.it("converts to uppercase", fun ()
test.assert_eq("hello".upper(), "HELLO")
end)
end)
test.it(name, fn) #
Define a single test case
Parameters:
name- Test name/description (Str)fn- Test function to execute
Example:
test.it("adds numbers correctly", fun ()
test.assert_eq(2 + 2, 4)
end)
test.before(fn) #
Run setup function before each test in current suite
Parameters:
fn- Setup function
Example:
test.describe("Database tests", fun ()
test.before(fun ()
db.connect()
db.clear()
end)
test.it("inserts records", fun ()
db.insert("users", {"name": "Alice"})
test.assert_eq(db.count("users"), 1)
end)
end)
test.after(fn) #
Run teardown function after each test in current suite
Parameters:
fn- Teardown function
Example:
test.describe("File tests", fun ()
test.after(fun ()
io.remove("test_output.txt")
end)
test.it("writes to file", fun ()
io.write("test_output.txt", "data")
test.assert(io.exists("test_output.txt"))
end)
end)
test.before_all(fn) #
Run setup once before all tests in suite
Parameters:
fn- Setup function
test.after_all(fn) #
Run teardown once after all tests in suite
Parameters:
fn- Teardown function
Assertions #
test.assert(condition, message = nil) #
Assert that condition is true
Parameters:
condition- Boolean condition (Bool)message- Optional failure message (Str)
Raises: AssertionError if condition is false
Example:
test.assert(5 > 3)
test.assert(user.is_admin(), "User must be admin")
test.assert_eq(actual, expected, message = nil) #
Assert that two values are equal
Parameters:
actual- Actual valueexpected- Expected valuemessage- Optional failure message (Str)
Example:
test.assert_eq(2 + 2, 4)
test.assert_eq("hello".len(), 5, "Wrong string length")
test.assert_neq(actual, expected, message = nil) #
Assert that two values are not equal
Parameters:
actual- Actual valueexpected- Value that should not matchmessage- Optional failure message (Str)
Example:
test.assert_neq(result)test.assert_neq(user_id, previous_id)
test.assert_gt(actual, expected, message = nil) #
Assert that actual is greater than expected
Parameters:
actual- Actual value (Num)expected- Expected threshold (Num)message- Optional failure message (Str)
Example:
test.assert_gt(score, 100)
test.assert_lt(actual, expected, message = nil) #
Assert that actual is less than expected
Parameters:
actual- Actual value (Num)expected- Expected threshold (Num)message- Optional failure message (Str)
test.assert_gte(actual, expected, message = nil) #
Assert that actual is greater than or equal to expected
test.assert_lte(actual, expected, message = nil) #
Assert that actual is less than or equal to expected
test.assert_nil(value, message = nil) #
Assert that value is nil
Parameters:
value- Value to checkmessage- Optional failure message (Str)
Example:
test.assert_nil(optional_param)
test.assert_not_nil(value, message = nil) #
Assert that value is not nil
Example:
test.assert_not_nil(result, "Result should not be nil")
test.assert_type(value, type_name, message = nil) #
Assert that value is of specific type
Parameters:
value- Value to checktype_name- Expected type name (Str): "Num", "Str", "Bool", "List", etc.message- Optional failure message (Str)
Example:
test.assert_type(result, "Num")
test.assert_type(names, "List")
test.assert_contains(collection, item, message = nil) #
Assert that collection contains item
Parameters:
collection- List or string to searchitem- Item to findmessage- Optional failure message (Str)
Example:
test.assert_contains([1, 2, 3], 2)
test.assert_contains("hello world", "world")
test.assert_not_contains(collection, item, message = nil) #
Assert that collection does not contain item
Example:
test.assert_not_contains(banned_users, user_id)
test.assert_len(collection, expected_len, message = nil) #
Assert that collection has expected length
Parameters:
collection- List or stringexpected_len- Expected length (Num)message- Optional failure message (Str)
Example:
test.assert_len(results, 10)
test.assert_len("hello", 5)
test.assert_empty(collection, message = nil) #
Assert that collection is empty
Example:
test.assert_empty([])
test.assert_empty("")
test.assert_not_empty(collection, message = nil) #
Assert that collection is not empty
test.assert_raises(fn, error_type = nil, message = nil) #
Assert that function raises an error
Parameters:
fn- Function to executeerror_type- Optional expected error type (Str)message- Optional failure message (Str)
Example:
test.assert_raises(fun ()
1 / 0
end)
test.assert_raises(fun ()
io.read("nonexistent.txt")
end, "FileNotFoundError")
test.assert_matches(text, pattern, message = nil) #
Assert that text matches regex pattern
Parameters:
text- Text to match (Str)pattern- Regex pattern (Str)message- Optional failure message (Str)
Example:
test.assert_matches(email, "^[a-z]+@[a-z]+\\.[a-z]+$")
test.assert_near(actual, expected, tolerance = 0.0001, message = nil) #
Assert that numbers are approximately equal (for floating point)
Parameters:
actual- Actual value (Num)expected- Expected value (Num)tolerance- Acceptable difference (Num, default 0.0001)message- Optional failure message (Str)
Example:
test.assert_near(math.pi, 3.14159, 0.00001)
test.assert_near(result, 2.5, 0.1)
Test Control #
test.skip(reason = nil) #
Skip current test
Parameters:
reason- Optional reason for skipping (Str)
Example:
test.it("integration test", fun ()
if !has_network()
test.skip("No network connection")
end
# test code...
end)
test.skip_if(condition, reason = nil) #
Skip test if condition is true
Parameters:
condition- Boolean condition (Bool)reason- Optional reason (Str)
Example:
test.it("runs on Unix only", fun ()
test.skip_if(sys.platform() == "windows", "Unix only")
# test code...
end)
test.fail(message) #
Explicitly fail the test
Parameters:
message- Failure message (Str)
Example:
test.it("validates behavior", fun ()
if weird_edge_case()
test.fail("Unexpected edge case encountered")
end
end)
Test Running #
test.run() #
Run all defined tests and print results
Returns: Exit code (Num): 0 if all pass, 1 if any fail
Example:
# At end of test file
test.run()
test.run_file(path) #
Load and run tests from file
Parameters:
path- Path to test file (Str)
Returns: Exit code (Num)
Example:
test.run_file("tests/string_test.q")
test.run_dir(path) #
Run all test files in directory
Parameters:
path- Directory path (Str)
Returns: Exit code (Num)
Example:
# Run all tests in tests/ directory
test.run_dir("tests")
Test Output #
test.set_reporter(reporter) #
Set output reporter style
Parameters:
reporter- Reporter name (Str): "default", "verbose", "minimal", "json", "tap"
Example:
test.set_reporter("verbose")
test.run()
test.set_color(enabled) #
Enable or disable colored output
Parameters:
enabled- Whether to use colors (Bool)
Mocking and Stubbing #
test.stub(obj, method, replacement) #
Replace method with stub for testing
Parameters:
obj- Object to stubmethod- Method name (Str)replacement- Replacement function
Returns: Stub handle for cleanup
Example:
test.it("mocks API call", fun ()
let stub = test.stub(api, "fetch", fun (url)
return {"status": 200, "data": "mock"}
end)
let result = api.fetch("http://example.com")
test.assert_eq(result.status, 200)
stub.restore()
end)
test.spy(fn) #
Create spy that tracks function calls
Parameters:
fn- Function to spy on
Returns: Spy object with call tracking
Example:
let spy = test.spy(callback)
do_something(spy)
test.assert(spy.called())
test.assert_eq(spy.call_count(), 2)
test.assert_eq(spy.calls[0].args, [1, 2, 3])
Test Fixtures #
test.fixture(name, fn) #
Define reusable test fixture
Parameters:
name- Fixture name (Str)fn- Function that returns fixture data
Example:
test.fixture("sample_users", fun ()
return [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
]
end)
test.it("processes users", fun ()
let users = test.use_fixture("sample_users")
test.assert_len(users, 2)
end)
Benchmarking #
test.benchmark(name, fn, iterations = 1000) #
Benchmark function execution time
Parameters:
name- Benchmark name (Str)fn- Function to benchmarkiterations- Number of iterations (Num, default 1000)
Example:
test.benchmark("string concatenation", fun ()
let s = ""
for i in 1..100
s = s + "x"
end
end, 1000)
Complete Example #
# tests/calculator_test.q
test.describe("Calculator", fun ()
test.describe("addition", fun ()
test.it("adds positive numbers", fun ()
test.assert_eq(calc.add(2, 3), 5)
end)
test.it("adds negative numbers", fun ()
test.assert_eq(calc.add(-2, -3), -5)
end)
test.it("handles zero", fun ()
test.assert_eq(calc.add(0, 5), 5)
test.assert_eq(calc.add(5, 0), 5)
end)
end)
test.describe("division", fun ()
test.it("divides numbers", fun ()
test.assert_eq(calc.div(10, 2), 5)
end)
test.it("handles decimal results", fun ()
test.assert_near(calc.div(7, 3), 2.333, 0.01)
end)
test.it("raises error on division by zero", fun ()
test.assert_raises(fun ()
calc.div(5, 0)
end, "DivisionByZeroError")
end)
end)
end)
# Run all tests
test.run()
Command Line Usage #
# Run single test file
quest tests/calculator_test.q
# Run all tests in directory
quest -test tests/
# Run with verbose output
quest -test -verbose tests/
# Run specific test
quest -test -only "Calculator addition" tests/calculator_test.q