๐งช Testing
Coppermind provides a mock mode for testing your data logic without hitting real DataStores.
โก Enabling Mock Modeโ
-- Enable mock mode
Coppermind.setMockMode(true)
-- Check if mock mode is enabled
if Coppermind.isMockMode() then
print("Running in mock mode")
end
-- Disable mock mode
Coppermind.setMockMode(false)
๐ฎ Mock Mode Behaviorโ
What Mock Mode Does
In mock mode, all data operations are simulated in memory!
| Feature | Behavior |
|---|---|
| ๐พ Storage | Data stored in memory |
| โก Speed | Operations complete nearly instantly |
| ๐ Rate Limits | No rate limiting or budget concerns |
| ๐ Session Locking | Still works (simulated) |
| ๐ฏ Use Cases | Unit tests & local development |
๐๏ธ Clearing Mock Dataโ
Reset all mock data between tests:
Coppermind.clearMockData()
This clears:
- โ All stored mock data
- โ All mock escrow/transaction data
๐งช Testing Patternsโ
๐๏ธ Basic Test Setupโ
local function runTests()
-- Enable mock mode
Coppermind.setMockMode(true)
Coppermind.clearMockData()
-- Run tests...
testDataOperations()
testTransactions()
testMigrations()
-- Cleanup
Coppermind.setMockMode(false)
end
- ๐ Data Operations
- ๐พ Persistence
- ๐ Transactions
- โ Failed Transactions
- ๐ข Events
local function testDataOperations()
local testKey = "test_player"
-- Load store
local store = Coppermind.loadStore(PlayerSchema, testKey, {})
task.wait(0.2) -- Wait for async load
-- Verify initial data
local data = Coppermind.getData(PlayerSchema, testKey)
assert(data.coins == 0, "Initial coins should be 0")
-- Test update
Coppermind.updateData(PlayerSchema, testKey, function(d)
d.coins = 100
return nil
end)
data = Coppermind.getData(PlayerSchema, testKey)
assert(data.coins == 100, "Coins should be 100 after update")
-- Cleanup
Coppermind.unloadStore(PlayerSchema, testKey)
task.wait(0.1)
print("โ Data operations test passed")
end
local function testPersistence()
local testKey = "persistence_test"
-- First session: save data
local store1 = Coppermind.loadStore(PlayerSchema, testKey, {})
task.wait(0.2)
Coppermind.updateData(PlayerSchema, testKey, function(data)
data.coins = 500
return nil
end)
Coppermind.saveStore(PlayerSchema, testKey)
task.wait(0.2)
Coppermind.unloadStore(PlayerSchema, testKey)
task.wait(0.2)
-- Second session: verify data persisted
local store2 = Coppermind.loadStore(PlayerSchema, testKey, {})
task.wait(0.2)
local data = Coppermind.getData(PlayerSchema, testKey)
assert(data.coins == 500, "Coins should persist after reload")
Coppermind.unloadStore(PlayerSchema, testKey)
task.wait(0.1)
print("โ Persistence test passed")
end
local function testTransactions()
local keyA = "player_a"
local keyB = "player_b"
-- Setup both stores
Coppermind.loadStore(PlayerSchema, keyA, {})
Coppermind.loadStore(PlayerSchema, keyB, {})
task.wait(0.2)
-- Give player A some coins
Coppermind.updateData(PlayerSchema, keyA, function(data)
data.coins = 1000
return nil
end)
-- Execute transaction
local success, result = Coppermind.transaction(
PlayerSchema,
keyA,
keyB,
function(dataA, dataB)
dataA.coins -= 500
dataB.coins += 500
return true
end
)
assert(success, "Transaction should succeed")
local dataA = Coppermind.getData(PlayerSchema, keyA)
local dataB = Coppermind.getData(PlayerSchema, keyB)
assert(dataA.coins == 500, "Player A should have 500 coins")
assert(dataB.coins == 500, "Player B should have 500 coins")
-- Cleanup
Coppermind.unloadStore(PlayerSchema, keyA)
Coppermind.unloadStore(PlayerSchema, keyB)
task.wait(0.1)
print("โ Transaction test passed")
end
local function testFailedTransaction()
local keyA = "player_a"
local keyB = "player_b"
Coppermind.loadStore(PlayerSchema, keyA, {})
Coppermind.loadStore(PlayerSchema, keyB, {})
task.wait(0.2)
-- Player A has 0 coins (default)
local success, errorMsg = Coppermind.transaction(
PlayerSchema,
keyA,
keyB,
function(dataA, dataB)
if dataA.coins < 100 then
return false, "Not enough coins"
end
dataA.coins -= 100
dataB.coins += 100
return true
end
)
assert(not success, "Transaction should fail")
assert(errorMsg == "Not enough coins", "Error message should match")
-- Verify no changes were made
local dataA = Coppermind.getData(PlayerSchema, keyA)
local dataB = Coppermind.getData(PlayerSchema, keyB)
assert(dataA.coins == 0, "Player A coins should be unchanged")
assert(dataB.coins == 0, "Player B coins should be unchanged")
Coppermind.unloadStore(PlayerSchema, keyA)
Coppermind.unloadStore(PlayerSchema, keyB)
task.wait(0.1)
print("โ Failed transaction test passed")
end
local function testEvents()
local testKey = "event_test"
local events = {
ready = false,
saved = false,
}
local store = Coppermind.loadStore(PlayerSchema, testKey, {})
store.onReady:Connect(function()
events.ready = true
end)
store.onSaved:Connect(function()
events.saved = true
end)
task.wait(0.2)
assert(events.ready, "onReady should fire")
Coppermind.saveStore(PlayerSchema, testKey)
task.wait(0.2)
assert(events.saved, "onSaved should fire")
Coppermind.unloadStore(PlayerSchema, testKey)
task.wait(0.1)
print("โ Events test passed")
end
โณ Waiting for Async Operationsโ
Async Operations
Mock mode operations are still asynchronous. Always wait properly!
- โฑ๏ธ Wait with Timeout
- ๐ข Use Events
- ๐ Poll State
local store = Coppermind.loadStore(schema, key, {})
task.wait(0.2)
local store = Coppermind.loadStore(schema, key, {})
store.onReady:Wait() -- Blocks until ready
local store = Coppermind.loadStore(schema, key, {})
while store.state == "LOADING" do
task.wait(0.05)
end
๐ Complete Test Suite Exampleโ
local function runTestSuite()
print("Starting Coppermind test suite...")
Coppermind.setMockMode(true)
local tests = {
{ name = "Data Operations", fn = testDataOperations },
{ name = "Persistence", fn = testPersistence },
{ name = "Transactions", fn = testTransactions },
{ name = "Failed Transactions", fn = testFailedTransaction },
{ name = "Events", fn = testEvents },
}
local passed = 0
local failed = 0
for _, test in tests do
Coppermind.clearMockData()
local success, err = pcall(test.fn)
if success then
passed += 1
else
failed += 1
warn(`โ {test.name}: {err}`)
end
end
Coppermind.setMockMode(false)
print(`\nResults: {passed}/{passed + failed} tests passed`)
end
โ Testing Checklistโ
| Test Type | What to Verify |
|---|---|
| ๐ Data Operations | Read, write, update cycles work correctly |
| ๐พ Persistence | Data survives save/load cycles |
| ๐ Transactions | Atomic operations commit/rollback properly |
| โ Failure Cases | Errors are handled gracefully |
| ๐ข Events | All lifecycle events fire correctly |
| ๐ Migrations | Old data formats upgrade properly |