assume: and observe:
EventFlow uses natural language constructs for test doubles: assume: to control behavior, observe: to watch without changing.
assume: System
assume: changes behavior for the test. Guards return specified values, actions behave as specified.
Core Principles
- Isolated - Each test has its own assumptions, no leakage
- Partial by default - Only specified behaviors change, rest runs normally
- Natural language - Reference by readable action/guard text
Guard Assumptions
Force guards to return specific values:
flow
assume:
// Force guard result
? customer is premium = true
? cart is valid = false
? payment successful = false
// Any comparison
? $total > {any} = true
// Pattern matching
? customer has * = true // All "customer has X" guardsAction Assumptions
Control how actions behave:
flow
assume:
// Success
validate cart = success
// Return value
process payment returns { transaction_id: "TXN-123" }
// Throw error
process payment throws "Connection timeout"
process payment throws { code: 500, message: "Server error" }
// Conditional (partial)
process payment with { amount: > 10000 } triggers :fraud_review
process payment with { amount: <= 10000 } = successTargeting Strategies
When multiple similar actions/guards exist:
Simple Name (when unique)
flow
assume:
process payment throws "Error"Full Text (when ambiguous)
flow
assume:
send confirmation email to @customer throws "SMTP error"
send notification to @warehouse = successPattern Matching
flow
assume:
send * to @customer throws "SMTP error" // Any send to customerEvent Scope
flow
assume:
in :checkout
send email throws "Error"
in :refund
send email = successParameter Matching
flow
assume:
process payment with { amount: > 10000 } triggers :fraud_review
send email with { template: "reminder" } throws "Not configured"observe: System
observe: watches actions without changing behavior. Real code runs, but calls are recorded for verification.
Core Principles
- Real execution - Action runs normally
- Observation only - Doesn't change behavior
- Verification - Check if/how action was called
Basic Usage
flow
test:
notifications sent correctly:
observe:
send confirmation email
update inventory
// Was it called?
= send confirmation email was called
= update inventory was not called
// How many times?
= send confirmation email was called 1 time
= send confirmation email was called at least 2 times
// With what parameters?
= send confirmation email was called with:
to: @customer.email
subject: contains "Order Confirmed"
// Call order
= send confirmation email was called before update inventoryCombining assume: and observe:
Use both when you need to control some behaviors and verify others:
flow
test:
payment fails - no email sent:
assume:
process payment throws "Declined"
observe:
send confirmation email
update inventory
= order is in #payment_failed
= send confirmation email was not called
= update inventory was not called
successful payment - verify notifications:
assume:
process payment returns { transaction_id: "TXN-123" }
observe:
send confirmation email
= order is in #paid
= send confirmation email was called with:
transaction_id: "TXN-123"Complete Example
flow
// order.test.flow
test: @order
for scenario: complete checkout
for :checkout:
payment gateway down:
assume:
? payment_gateway is available = false
= order is in #queued
email fails but order succeeds:
assume:
send confirmation email throws "SMTP error"
observe:
send pick notification to @warehouse
= order is in #confirmed
= send pick notification to @warehouse was called
= email failure was logged
fraud check for high value:
with context:
$total is 5000
assume:
? fraud detected = false
observe:
check fraud
= check fraud was called
= order is in #confirmedassume: vs observe:
| Feature | assume: | observe: |
|---|---|---|
| Changes behavior | Yes | No |
| Real code runs | No (replaced) | Yes |
| Records calls | No | Yes |
| Use case | Force specific outcomes | Verify side effects |
When to use assume:
- Testing error paths
- Forcing guard branches
- Simulating external failures
- Testing with specific return values
When to use observe:
- Verifying side effects occur
- Checking call parameters
- Ensuring actions are NOT called
- Validating call order
Assertion Patterns for observe:
flow
// Basic call check
= action was called
= action was not called
// Call count
= action was called 3 times
= action was called at least 1 time
= action was called at most 5 times
// Parameters
= action was called with:
param1: "value"
param2: contains "partial"
param3: > 100
// Order
= action1 was called before action2
= action1 was called after action2
// Actor-specific
= send email to @customer was called
= emit :notification to @warehouse was called