achedon12 / golem
Integration tests for PocketMine-MP plugins: a real server, simulated players, one command.
Requires
- php: ^8.1
Requires (Dev)
- phpstan/phpstan: ^2.1
- pocketmine/pocketmine-mp: ^5.44
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v0.x-dev
- v0.7.0
- v0.6.0
- v0.5.1
- v0.5.0
- v0.4.0
- v0.3.0
- v0.2.0
- v0.1.1
- v0.1.0
- v0
- dev-release/0.7.0
- dev-feature/compat
- dev-feature/pr-report
- dev-feature/mutate
- dev-feature/ui-watch
- dev-feature/flaky
- dev-docs/youtube-video
- dev-release/0.6.0
- dev-docs/demo-failure-note
- dev-release/0.5.1
- dev-fix/ui-keep-hash
- dev-release/0.5.0
- dev-docs/dashboard-demo
- dev-feature/ui-history
- dev-feature/ui-scenarios
- dev-feature/ui-fuzz-bench
- dev-feature/ui-server
- dev-docs/versions
- dev-docs/downloads-badge
- dev-release/0.4.0
- dev-feature/record
- dev-feature/line-coverage
- dev-feature/teamcity
- dev-feature/parallel
- dev-feature/bench-baseline
- dev-feature/fuzz-tests
- dev-feature/many-golems
- dev-feature/bench
- dev-feature/fuzz
- dev-feature/coverage
- dev-feature/compare
- dev-feature/snapshots
- dev-fix/isolated-action-cache
- dev-release/0.3.0
- dev-feature/forks
- dev-feature/phar-releases
- dev-fix/no-golem-player-data
- dev-fix/golem-identity
- dev-feature/server-plugin
- dev-release/0.2.0
- dev-feature/watch-mode
- dev-feature/inventory-menus
- dev-feature/world-templates
- dev-feature/entities-and-respawn
- dev-feature/scoreboards-boss-bars
- dev-feature/data-providers
- dev-feature/kick-assertions
- dev-feature/movement
- dev-fix/harden-virion-downloads
- dev-feature/virions
- dev-feature/fresh-world
- dev-feature/sound-and-packet-assertions
This package is auto-updated.
Last update: 2026-10-08 13:16:15 UTC
README
Golem tests your PocketMine-MP plugin the way your players use it. One command boots a real
server, loads your plugin from source, spawns simulated players (golems) that join, chat, run
commands, click forms and break blocks, then checks what happened. No mocks, no client, no manual
testing on a local server ever again. Run it in your terminal, in CI, or from a dashboard in your
browser (vendor/bin/golem ui, live demo).
final class WelcomeTest extends TestCase { public function testGreetsPlayersByName(): Generator { $steve = yield $this->golem('Steve'); // a real Player joins the server $this->assertReceivedMessage($steve, 'Welcome, Steve!'); $this->assertHasItem($steve, VanillaItems::BREAD(), 3); } public function testMenuTeleportsToSpawn(): Generator { $steve = yield $this->golem('Steve'); $steve->teleport($this->spawn()->add(40, 0, 40)); $steve->chat('/menu'); $steve->clickButton('Spawn'); // answer the form like a player would $this->assertAt($steve, $this->spawn()); } }
Why Golem
Unit tests stop where PocketMine starts: events, permissions, forms, inventories, scheduling and worlds all need a running server. So most plugins are tested by hand, by joining a local server and trying things. Golem automates exactly that:
- A real server. Your plugin runs on the PocketMine-MP version you choose, with every event fired in the real order. If it works in Golem, it works in production.
- Simulated players. Golems are genuine
Playerobjects behind a fake network session. They go through login and spawn, soPlayerJoinEventand friends fire exactly as usual. - Time is a first-class citizen.
yield $this->wait(20)lets a second pass;waitUntil()polls a condition tick by tick. Cooldowns, delayed tasks and async work are testable. - Zero setup. Golem downloads the official PocketMine PHP build and server phar, caches them, and creates a fresh world for every run.
- A dashboard.
vendor/bin/golem uiruns your tests in the browser, shows failures next to the code and coverage line by line, and builds tests without writing PHP. - Finds what you missed.
golem fuzzturns random golem actions into crash reports and tests;golem benchmeasures how many players your plugin holds. - Made for CI. JUnit reports, a one-line GitHub Action, and failures annotated right on the pull request diff.
Installation
composer require --dev achedon12/golem vendor/bin/golem init # adds tests/ExampleTest.php and a GitHub Actions workflow vendor/bin/golem # runs your tests
Golem needs PHP 8.1+ on your machine to run the CLI, on Linux or macOS (on Windows, use WSL). The server itself runs on PocketMine's own PHP build, which Golem downloads once.
Composer is only there to give your IDE autocompletion. The CLI has no dependencies, so you can
also clone this repository and run php path/to/golem/bin/golem from your plugin folder.
Writing tests
Tests live in tests/ next to your plugin.yml. Each public method starting with test runs on
the server's main thread, after your plugin is enabled. A test that needs time to pass is a
generator: yield what you are waiting for and Golem resumes the test when it is ready.
public function testHealCooldown(): Generator { $steve = yield $this->golem('Steve'); $steve->op()->player()->setHealth(4); $steve->chat('/heal'); $steve->player()->setHealth(4); $steve->chat('/heal'); $this->assertHealth($steve, 4); // still on cooldown yield $this->wait(5 * 20); // five seconds later... $steve->chat('/heal'); $this->assertHealth($steve, 20); }
| A golem can | Then you can check |
|---|---|
chat(), command() |
messages(), titles(), actionBars(), tips(), popups(), toasts() |
clickButton(), submitForm(), closeForm() |
form(), formData() |
clickSlot(), closeWindow() in chest menus (InvMenu works) |
window() |
walkTo(), walk(), jump(), sneak(), sprint() |
position(), fall damage, PlayerMoveEvent in your plugin |
breakBlock(), interactBlock(), interactEntity(), useItem(), attack() |
scoreboard(), bossBar(), sounds() |
op(), grant(), gamemode(), teleport(), give(), hold(), respawn(), quit() |
disconnectReason(), packets(), and player() for the full PocketMine API |
On top of the usual assertSame, assertTrue, assertCount… you get Minecraft-aware assertions:
assertReceivedMessage, assertTitle, assertFormOpen, assertWindowOpen, assertScoreboardContains,
assertBossBar, assertSoundPlayed, assertHasItem, assertHealth, assertAt, assertBlockAt,
assertKicked, assertDead and more.
Tests can run in a throwaway world (#[FreshWorld]) or a copy of your map (#[World('tests/worlds/arena')]),
take data sets (#[DataProvider]), and plugins using virions just work: Golem reads your .poggit.yml.
Keep vendor/bin/golem --watch open while you code to re-run everything on each save.
When something breaks, Golem tells you what it expected, what it got, and where:
On a development server
Golem is also a plugin: put Golem.phar in your dev server's
plugins/ folder and spawn simulated players by hand, to try a minigame or a duel alone:
/golem spawn Rival
/golem Rival chat /duel accept
/golem Rival inbox
Play a scenario by hand with /golem record, and /golem record stop writes a test that replays
it. See Server plugin for every command.
Dashboard
vendor/bin/golem ui opens a dashboard on localhost: run the tests and follow them live, read
failures and coverage in the code, fuzz, benchmark, and build tests without writing PHP.
Try the live demo or read Dashboard.
Fuzzing
golem fuzz has golems do random things to your plugin for a minute (commands with odd
arguments, invalid form answers, clicks, disconnections) and reports every exception with the
actions that led to it and a seed to replay them. See Fuzzing.
Mutation testing
golem mutate changes your code one small mutation at a time (=== into !==, < into <=,
true into false…) and runs the tests that cover each line: the mutants nobody notices are the
bugs your tests would let through. See Mutation testing.
Compatibility
golem compat EssentialsMP libs/Economy.phar runs your tests alone, then with other plugins
loaded next to yours, and shows the tests that break and the commands another plugin takes. See
Compatibility.
Benchmark
golem bench --players=100 brings golems in a few at a time and shows how TPS, tick usage and
memory evolve, then the plugin's slowest listeners. assertTpsAbove(18.0) catches a slowdown in a
test. See Benchmark.
Continuous integration
# .github/workflows/tests.yml name: Tests on: [push, pull_request] jobs: golem: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: achedon12/golem@v0
The action caches PocketMine between runs, writes golem-junit.xml, and annotates failures on
the pull request. See docs/ci.md for the options and for other CI systems.
Documentation
📖 achedon12.github.io/golem, with search. The same pages are
in the wiki and in docs/:
- Getting started
- Writing tests: structure, waiting, setUp, attributes
- Golems: everything a simulated player can do
- Assertions: the full list
- Configuration: CLI options and
composer.jsonsettings - Continuous integration
- How it works, including the current limitations
Status
Golem is young (0.x): the API may still change between minor versions, and the
changelog will say so. It targets PocketMine-MP 5, which reached its end of support
in July 2026, and its forks: --pocketmine=owner/repository tests your plugin on the fork your
server runs (see forks). Ideas, bug reports and pull
requests are very welcome, see CONTRIBUTING.md.
License
MIT © Achedon12

