# Test Features

> A comprehensive guide for creating test instances and test environments in Minecraft's GameTest framework with Kore.

Updated 2026-10-21. Canonical: https://kore.ayfri.com/docs/advanced/test-features

Minecraft 1.21.5 (Snapshot 25w03a) introduced a major overhaul to the **GameTest framework** - an automated end-to-end testing system for
datapack functionality. Kore provides a type-safe Kotlin DSL that generates JSON files for the `test_instance` and `test_environment`
registries.

## Test Environments

Test environments define the preconditions under which tests run. There are seven types:

### Weather

Sets a fixed weather condition:

```kotlin
testEnvironments {
	weather("clear_weather", Weather.CLEAR)
	weather("rain_weather", Weather.RAIN)
	weather("storm_weather", Weather.THUNDER)
}
```

### Clock Time

Locks a world clock to a specific tick value:

```kotlin
testEnvironments {
	clockTime("morning", WorldClocks.OVERWORLD, 1000)
	clockTime("noon", WorldClocks.OVERWORLD, 6000)
	clockTime("night", WorldClocks.OVERWORLD, 18000)
}
```

### Difficulty

Forces the game difficulty, keeping difficulty-dependent mechanics deterministic:

```kotlin
testEnvironments {
	difficulty("peaceful_env", Difficulty.PEACEFUL)
	difficulty("hard_env", Difficulty.HARD)
}
```

### Game Rules

Overrides game rules for controlled conditions:

```kotlin
testEnvironments {
	gameRules("controlled_env") {
		this[Gamerules.ADVANCE_TIME] = false
		this[Gamerules.SPAWN_MOBS] = false
		this[Gamerules.RANDOM_TICK_SPEED] = 0
	}
}
```

### Function

Runs datapack functions before (`setup`) and/or after (`teardown`) each test:

```kotlin
val setupFn = function("test_setup") { say("Setting up") }
val teardownFn = function("test_teardown") { say("Tearing down") }

testEnvironments {
	function("my_function_env") {
		setup(setupFn)
		teardown(teardownFn)
	}
}
```

### Timeline Attributes

Applies a set of timelines during test execution, useful for testing time-driven mechanics:

```kotlin
val dayCycle = timeline("day_cycle", WorldClocks.OVERWORLD)
val endCycle = timeline("end_cycle", WorldClocks.THE_END)

testEnvironments {
	timelineAttributes("timeline_env", dayCycle, endCycle)
}
```

### Combined (allOf)

Merges multiple environments into one:

```kotlin
testEnvironments {
	val rules = gameRules("no_mobs") {
		this[Gamerules.SPAWN_MOBS] = false
	}
	val time = clockTime("dawn", WorldClocks.OVERWORLD, 1000)

	allOf("controlled_dawn", rules, time)
}
```

> **Tip:** You can also create environments outside a `testEnvironments` block using `testEnvironmentsBuilder`:
> ```kotlin
> val env = testEnvironmentsBuilder.weather("clear", Weather.CLEAR)
> ```
> This is useful when reusing environments across multiple test instances.

## Test Instances

Test instances define the actual tests. Each one references a structure, an environment, and execution parameters.

### Test Types

- **Block-based** (`blockBased()`): Test logic is driven by redstone inside the structure using special test blocks (Start, Log, Fail,
  Accept).
- **Function-based** (`functionBased()`): Test logic is handled by a Java method reference (used by Mojang internally and mod developers).
  Requires a `function` field with a fully qualified method reference (e.g., `"com.example.MyMod::myTest"`).

### Creating Test Instances

```kotlin
testInstances {
	// Block-based test
	testInstance("redstone_test") {
		blockBased()
		environment(env)
		maxTicks = 100
		structure(Structures.AncientCity.Structures.BARRACKS)
	}

	// Function-based test
	testInstance("function_test") {
		functionBased()
		environment(env)
		function("com.example.MyMod::myTest")
		maxTicks = 200
		structure(Structures.Igloo.TOP)
	}
}
```

### Configuration Options

All available properties for a test instance:

| Property                           | Type                      | Description                                          |
|------------------------------------|---------------------------|------------------------------------------------------|
| `environment(env)`                 | `TestEnvironmentArgument` | **Required.** The test environment to use.           |
| `structure(struct)`                | `StructureArgument`       | **Required.** The structure template for the test.   |
| `blockBased()` / `functionBased()` | -                         | Sets the test type (default: block-based).           |
| `function(fn)`                     | `String`                  | Java method reference for function-based tests.      |
| `maxTicks`                         | `Int`                     | Maximum ticks before timeout (default: 100).         |
| `setupTicks`                       | `Int`                     | Ticks to wait before starting the test.              |
| `maxAttempts`                      | `Int`                     | Maximum retry attempts.                              |
| `requiredSuccesses`                | `Int`                     | Successes needed out of `maxAttempts`.               |
| `required`                         | `Boolean`                 | Whether the test must pass for the suite to succeed. |
| `manualOnly`                       | `Boolean`                 | Whether the test is only run manually.               |
| `skyAccess`                        | `Boolean`                 | Whether the structure needs sky access.              |
| `dimension`                        | `DimensionArgument`       | Dimension the test runs in (default: overworld).     |
| `rotation(rot)`                    | `StructureRotation`       | Rotation applied to the structure.                   |

Rotation helpers: `noRotation()`, `clockwise90()`, `rotate180()`, `counterclockwise90()`.

## Structures

Kore provides constants for all vanilla structures:

```kotlin
// Examples
structure(Structures.AncientCity.Structures.BARRACKS)
structure(Structures.Bastion.Treasure.Bases.LAVA_BASIN)
structure(Structures.Igloo.TOP)
structure(Structures.TrialChambers.Chamber.ASSEMBLY)
structure(Structures.Village.Plains.Houses.PLAINS_SMALL_HOUSE_1)
```

## Test Commands

### Selectors

```kotlin
allTests()                     // "*:*" - all tests
minecraftTests()              // "minecraft:*" - minecraft tests
testSelector("my_pack:*")     // All tests in namespace
testSelector("*_combat")      // Pattern matching
```

### Command Usage

```kotlin
function("run_tests") {
	test {
		val selector = testSelector("my_pack:test_*")

		run(selector)
		runClosest()
		runMultiple(selector, 5)

		create(TestInstanceArgument("test", "pack"))
		locate(selector)
		pos("variable")

		clearAll()
		resetClosest()
		stop()

		verify(TestInstanceArgument("test1", "pack"))
	}
}
```

This generates:

```mcfunction
test run my_pack:test_*
test runclosest
test runmultiple my_pack:test_* 5
test create pack:test
test locate my_pack:test_*
test pos variable
test clearall
test resetclosest
test stop
test verify pack:test1
```

## Complete Example

```kotlin
fun DataPack.createTestSuite() {
	val setupFn = function("test_setup") { say("Setting up test") }
	val cleanupFn = function("test_cleanup") { say("Cleaning up test") }
	// Create reusable environments
	val controlled = testEnvironmentsBuilder.gameRules("controlled") {
		this[Gamerules.ADVANCE_TIME] = false
		this[Gamerules.SPAWN_MOBS] = false
		this[Gamerules.RANDOM_TICK_SPEED] = 0
	}
	val dayTime = testEnvironmentsBuilder.clockTime("day", WorldClocks.OVERWORLD, 6000)
	val controlledDay = testEnvironmentsBuilder.allOf("controlled_day", controlled, dayTime)

	// Function environment (setup/teardown)
	testEnvironments {
		function("test_functions") {
			setup(setupFn)
			teardown(cleanupFn)
		}
	}

	testInstances {
		testInstance("redstone_basic") {
			blockBased()
			environment(controlledDay)
			maxTicks = 100
			required = true
			structure(Structures.AncientCity.Structures.BARRACKS)
		}

		testInstance("complex_logic_test") {
			functionBased()
			environment(controlled)
			function("com.example.MyMod::myTest")
			maxAttempts = 2
			maxTicks = 200
			required = true
			structure(Structures.AncientCity.Structures.BARRACKS)
		}

		testInstance("directional_blocks") {
			blockBased()
			clockwise90()
			environment(controlled)
			maxTicks = 120
			required = true
			structure(Structures.AncientCity.Structures.BARRACKS)
		}
	}
}
```

## Best Practices

- **Combine environments** with `allOf` for complex scenarios.
- **Mark critical tests** as `required = true`.
- **Set appropriate timeouts** with `maxTicks`.
- **Use game rules** to disable randomness (mob spawning, daylight cycle, tick speed).
- **Reuse environments** via `testEnvironmentsBuilder` to avoid duplication.

## See Also

- [Functions](https://kore.ayfri.com/docs/commands/functions.md) - Kore's DSL for writing datapack functions.
- [GameTest Framework](https://minecraft.fandom.com/wiki/GameTest_Framework) - Official Minecraft documentation.
