cquill/testing
Types
A test context containing a memory store and tracking information.
The test context provides:
- A fresh memory store for database operations
- An auto-incrementing ID counter for generating unique IDs
- Tracking of inserted entities for verification
pub type TestContext {
TestContext(
store: memory.MemoryStore,
id_counter: Int,
inserted: dict.Dict(String, List(String)),
)
}
Constructors
-
TestContext( store: memory.MemoryStore, id_counter: Int, inserted: dict.Dict(String, List(String)), )Arguments
- store
-
The memory store for database operations
- id_counter
-
Counter for generating unique IDs in factories
- inserted
-
Tracks inserted entity IDs by table name for verification
Values
pub fn create_tables(
store: memory.MemoryStore,
tables: List(#(String, String)),
) -> memory.MemoryStore
Create multiple tables in the memory store.
Each table is specified as a tuple of (table_name, primary_key_column). This is a convenience function for setting up test fixtures.
Example
let store = create_tables(store, [
#("users", "id"),
#("posts", "id"),
#("comments", "id"),
])
pub fn get_store(ctx: TestContext) -> memory.MemoryStore
Get the memory store from a test context.
Example
let store = get_store(ctx)
let result = memory.get_row(store, "users", "1")
pub fn get_tracked(
ctx: TestContext,
table: String,
) -> List(String)
Get all tracked entity keys for a table.
Example
let keys = get_tracked(ctx, "users")
// Returns ["2", "1"] (most recent first)
pub fn new_context() -> TestContext
Create a new test context with a fresh memory store.
Example
let ctx = new_context()
// ctx.id_counter starts at 1
pub fn next_id(ctx: TestContext) -> #(TestContext, Int)
Generate the next unique ID for test data. Returns the updated context and the new ID.
IDs start at 1 and increment with each call.
Example
let #(ctx, id1) = next_id(ctx)
let #(ctx, id2) = next_id(ctx)
// id1 = 1, id2 = 2
pub fn next_ids(
ctx: TestContext,
count: Int,
) -> #(TestContext, List(Int))
Batch generate unique IDs.
Example
let #(ctx, ids) = next_ids(ctx, 3)
// ids = [1, 2, 3]
pub fn reset(ctx: TestContext) -> TestContext
Reset a test context, clearing all data but preserving table structure.
Useful for running multiple scenarios within the same test.
Example
// After first scenario
let ctx = reset(ctx)
// Tables still exist but are empty, ID counter resets to 1
pub fn set_store(
ctx: TestContext,
store: memory.MemoryStore,
) -> TestContext
Update the memory store in a test context.
Use this after performing operations that return a new store.
Example
let assert Ok(new_store) = memory.create_table(ctx.store, "users", [])
let ctx = set_store(ctx, new_store)
pub fn track_insert(
ctx: TestContext,
table: String,
key: String,
) -> TestContext
Track an inserted entity key for later verification or cleanup.
This is useful for tracking what entities were created during a test so you can verify they exist or clean them up.
Example
let ctx = track_insert(ctx, "users", "1")
let ctx = track_insert(ctx, "users", "2")
tracked_count(ctx, "users") // Returns 2
pub fn tracked_count(ctx: TestContext, table: String) -> Int
Get the count of tracked entities for a table.
Example
let count = tracked_count(ctx, "users")
// Returns number of entities tracked for "users" table
pub fn unique_email(ctx: TestContext) -> #(TestContext, String)
Generate a unique email for test data.
Convenience function that generates emails like “test_1@example.com”.
Example
let #(ctx, email1) = unique_email(ctx)
let #(ctx, email2) = unique_email(ctx)
// email1 = "test_1@example.com"
// email2 = "test_2@example.com"
pub fn unique_string(
ctx: TestContext,
prefix: String,
suffix: String,
) -> #(TestContext, String)
Generate a unique string for test data (useful for emails, usernames, etc.)
Combines prefix, unique ID, and suffix to create unique values.
Example
let #(ctx, email) = unique_string(ctx, "user", "@example.com")
// email = "user_1@example.com"
let #(ctx, username) = unique_string(ctx, "testuser", "")
// username = "testuser_2"
pub fn unique_username(
ctx: TestContext,
) -> #(TestContext, String)
Generate a unique username for test data.
Example
let #(ctx, username) = unique_username(ctx)
// username = "user_1"
pub fn with_context(test_fn: fn(TestContext) -> a) -> a
Run a test function with a fresh test context.
The context provides additional utilities like ID generation and entity tracking beyond what the raw memory store provides.
Example
pub fn multi_entity_test() {
use ctx <- with_context()
let #(ctx, user_id) = next_id(ctx)
let #(ctx, email) = unique_email(ctx)
// ... test code using the context
}
pub fn with_memory_store(
test_fn: fn(memory.MemoryStore) -> a,
) -> a
Run a test function with a fresh memory store.
This is the recommended way to write tests that need a memory store. Each test gets a completely fresh store, ensuring test isolation.
Example
pub fn insert_user_test() {
use store <- with_memory_store()
let assert Ok(store) = memory.create_table(store, "users", [])
// ... test code
}