Writing Tests
This guide shows how to write effective and maintainable tests.
Core Principles
Section titled “Core Principles”1. One Test, One Behavior
Section titled “1. One Test, One Behavior”Each test should verify exactly one behavior.
Bad:
{ "name": "Redstone works", "timeline": [ // Tests signal strength // Tests repeaters // Tests comparators // Tests lamps ]}Good:
{ "name": "Redstone signal loses 1 strength per block", "timeline": [ // Only signal strength decay ]}2. Meaningful Names
Section titled “2. Meaningful Names”The test name should describe the expected behavior.
Bad:
test1.jsonredstone.jsonblock-test.json
Good:
redstone-signal-loses-strength-per-block.jsonrepeater-4-tick-delay.jsonsand-falls-when-support-removed.json
3. Minimal Cleanup Region
Section titled “3. Minimal Cleanup Region”Use only as much space as needed.
Bad:
{ "cleanup": { "region": [[0, 0, 0], [14, 100, 14]] }}Good:
{ "cleanup": { "region": [[0, 0, 0], [5, 2, 0]] }}4. Atomic Setup with placeEach
Section titled “4. Atomic Setup with placeEach”Place all initial blocks in a single tick.
{ "timeline": [ { "at": 0, "do": "placeEach", "blocks": [ { "pos": [0, 0, 0], "block": { "id": "minecraft:stone" } }, { "pos": [1, 0, 0], "block": { "id": "minecraft:redstone_wire" } }, { "pos": [2, 0, 0], "block": { "id": "minecraft:redstone_wire" } } ] }, { "at": 1, "do": "place", "pos": [0, 1, 0], "block": { "id": "minecraft:redstone_block" } } ]}Test Structure
Section titled “Test Structure”Anatomy of a Test
Section titled “Anatomy of a Test”1. Setup (Tick 0) - Place initial blocks2. Action (Tick 1+) - Execute the action being tested3. Wait (optional) - Time for processing4. Assertion - Verify resultExample: Complete Test
Section titled “Example: Complete Test”{ "name": "Lever activates redstone lamp", "description": "Verifies that an activated lever turns on a connected lamp", "tags": ["redstone", "unit"], "setup": { "cleanup": { "region": [[0, 0, 0], [2, 1, 0]] } }, "timeline": [ { "at": 0, "do": "placeEach", "blocks": [ { "pos": [0, 0, 0], "block": { "id": "minecraft:redstone_lamp" } }, { "pos": [1, 0, 0], "block": { "id": "minecraft:redstone_wire" } }, { "pos": [2, 0, 0], "block": { "id": "minecraft:lever", "powered": false } } ] }, { "at": 0, "do": "assert", "checks": [ { "pos": [0, 0, 0], "is": { "id": "minecraft:redstone_lamp", "lit": false } } ] }, { "at": 1, "do": "place", "pos": [2, 0, 0], "block": { "id": "minecraft:lever", "powered": true } }, { "at": 2, "do": "assert", "checks": [ { "pos": [0, 0, 0], "is": { "id": "minecraft:redstone_lamp", "lit": true } } ] } ]}Using Assertions Effectively
Section titled “Using Assertions Effectively”Only Check Relevant Properties
Section titled “Only Check Relevant Properties”Only verify the properties that matter for your test.
Too specific:
{ "is": { "id": "minecraft:redstone_wire", "power": 15, "north": "side", "south": "side", "east": "none", "west": "none" }}Better:
{ "is": { "id": "minecraft:redstone_wire", "power": 15 }}Before-After Assertions
Section titled “Before-After Assertions”Check state before and after an action.
{ "timeline": [ { "at": 0, "do": "place", "pos": [0,0,0], "block": {"id": "minecraft:copper_block"} },
{ "at": 0, "do": "assert", "checks": [ { "pos": [0,0,0], "is": {"id": "minecraft:copper_block"} } ]},
{ "at": 1, "do": "useItemOn", "pos": [0,0,0], "face": "top", "item": "minecraft:honeycomb" },
{ "at": 2, "do": "assert", "checks": [ { "pos": [0,0,0], "is": {"id": "minecraft:waxed_copper_block"} } ]} ]}Multiple Assertions Over Time
Section titled “Multiple Assertions Over Time”For tests that verify stability:
{ "at": [10, 20, 30], "do": "assert", "checks": [ { "pos": [5, 0, 5], "is": { "id": "minecraft:redstone_lamp", "lit": true } } ]}Choosing the Right Timing
Section titled “Choosing the Right Timing”Redstone Timing
Section titled “Redstone Timing”{ "timeline": [ { "at": 0, "do": "placeEach", "blocks": [...] }, { "at": 1, "do": "place", "pos": [0,0,0], "block": {"id": "minecraft:redstone_block"} }, { "at": 2, "do": "assert", "checks": [...] } ]}Rule of thumb: Assert 1-2 ticks after a redstone change.
Falling Blocks
Section titled “Falling Blocks”Sand/gravel need time to fall:
{ "timeline": [ { "at": 0, "do": "placeEach", "blocks": [ { "pos": [0, 1, 0], "block": { "id": "minecraft:sand" } }, { "pos": [0, 0, 0], "block": { "id": "minecraft:stone" } } ]}, { "at": 1, "do": "remove", "pos": [0, 0, 0] }, { "at": 10, "do": "assert", "checks": [ { "pos": [0, 0, 0], "is": { "id": "minecraft:sand" } } ]} ]}Observer Chains
Section titled “Observer Chains”Observers have 2 game-tick delay:
{ "timeline": [ { "at": 0, "do": "placeEach", "blocks": [ { "pos": [0, 0, 0], "block": { "id": "minecraft:observer", "facing": "east" } }, { "pos": [1, 0, 0], "block": { "id": "minecraft:observer", "facing": "east" } } ]}, { "at": 1, "do": "place", "pos": [-1, 0, 0], "block": { "id": "minecraft:stone" } }, { "at": 3, "do": "assert", "checks": [ { "pos": [0, 0, 0], "is": { "id": "minecraft:observer", "powered": true } } ]}, { "at": 5, "do": "assert", "checks": [ { "pos": [1, 0, 0], "is": { "id": "minecraft:observer", "powered": true } } ]} ]}Debugging
Section titled “Debugging”Step-by-Step Verification
Section titled “Step-by-Step Verification”Add intermediate assertions:
{ "timeline": [ { "at": 0, "do": "place", ... }, { "at": 0, "do": "assert", "checks": [...] }, { "at": 1, "do": "place", ... }, { "at": 1, "do": "assert", "checks": [...] }, { "at": 2, "do": "assert", "checks": [...] } ]}Using Breakpoints
Section titled “Using Breakpoints”For debug sessions:
{ "breakpoints": [0, 5, 10], "timeline": [...]}Descriptive Descriptions
Section titled “Descriptive Descriptions”{ "name": "Repeater 4-tick delay", "description": "Verifies that a repeater on level 4 delays exactly 8 game ticks. Setup: Redstone block -> Wire -> Repeater(4) -> Wire. Expected: After 8 ticks the output wire is powered."}Contributing Your Tests
Section titled “Contributing Your Tests”Tests that validate vanilla Minecraft behavior should be contributed to FlintBench, the official test collection. This ensures tests are:
- Available to the entire community
- Properly organized and formatted
- Used to validate server implementations
See the FlintBench documentation for contribution guidelines.