Skip to content

Writing Tests

This guide shows how to write effective and maintainable tests.

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
]
}

The test name should describe the expected behavior.

Bad:

  • test1.json
  • redstone.json
  • block-test.json

Good:

  • redstone-signal-loses-strength-per-block.json
  • repeater-4-tick-delay.json
  • sand-falls-when-support-removed.json

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]]
}
}

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" }
}
]
}
1. Setup (Tick 0) - Place initial blocks
2. Action (Tick 1+) - Execute the action being tested
3. Wait (optional) - Time for processing
4. Assertion - Verify result
{
"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 } }
]
}
]
}

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
}
}

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"} }
]}
]
}

For tests that verify stability:

{
"at": [10, 20, 30],
"do": "assert",
"checks": [
{ "pos": [5, 0, 5], "is": { "id": "minecraft:redstone_lamp", "lit": true } }
]
}
{
"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.

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" } }
]}
]
}

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 } }
]}
]
}

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": [...] }
]
}

For debug sessions:

{
"breakpoints": [0, 5, 10],
"timeline": [...]
}
{
"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."
}

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.