/ build-in-public / How I Test A Godot Game I Built Alone With A Headless Smoke Suite
build-in-public 7 min read

How I Test A Godot Game I Built Alone With A Headless Smoke Suite

I have no QA team, so I built a headless smoke suite in Godot that instances every scene, round trips saves, sweeps 300 battle seeds, and enumerates the slot odds.

Orchard Deck campaign battle view with cards arranged front to back

I built Orchard Deck alone, which means there is no QA team, no testers, and nobody to catch the bug I just introduced except me. The game has six interlocking systems, a slot machine economy, a seeded battle simulation, ten arcade minigames, a save system that has to survive across versions, and 84 cards that feed every pool. Clicking through all of that by hand after every change is not a plan, it is a slow path to shipping something broken. So I built a headless smoke suite, and it is the single thing that lets me move fast without breaking the game.

A smoke test gets its name from hardware, where you power the board on and check that nothing literally smokes. A software smoke suite is the same idea, a fast pass that confirms the whole system boots and the critical paths work, run before every change so I never ship on a guess. Mine runs in Godot with no graphics, no window, no rendering, just the engine executing logic and reporting what passed.

Play Orchard Deck in your browser

Running Godot Headless

The foundation is that Godot can run with no display at all. You launch it in headless mode and it executes your scripts without ever opening a window or drawing a frame. That is the thing that makes automated testing possible for a game.

A game is normally inseparable from its rendering. You see a thing on screen, you click it, you watch what happens. That is wonderful for playing and useless for testing, because it requires a human eye and a human hand in the loop. Headless mode breaks game logic free from the visuals. I can instantiate a battle, run it to completion, and check the result in milliseconds without anything ever being drawn, so the whole suite runs fast enough that I treat it as a reflex, not a ceremony.

Instancing Every Scene

The cheapest and most valuable check in the suite is also the dumbest. I instance every single scene in the game and confirm it loads without crashing.

This check catches more than anything else in the suite. Scenes break in boring ways. A renamed node, a script reference that no longer resolves, a resource that got moved, a signal connected to a method that no longer exists. None of those throw an error until the scene actually loads, and in a manual workflow you only discover the broken scene when you happen to navigate to it, days later, after you have built ten things on top of the breakage. By instancing every scene on every run, I find the break the instant I cause it, while the change is still fresh in my head.

Round Tripping Saves And Migrating Old Ones

A collection game lives entirely in its save file. If a save corrupts, the player loses their whole orchard, and there is no excuse for that in a game where progress is the point. So the suite hammers the save system from two directions.

First, save and load round trips. The suite builds a game state, writes it to a save, reads it back, and confirms what came out matches what went in. Every card, every coin balance, every museum set, every tech tree upgrade has to survive the trip exactly. If serialization drops a field or mangles a value, the round trip catches it before a player ever does.

Second, and this is the one that helps a live game most, legacy save migration. Every time I add a system or change how something is stored, old save files have a shape my new code does not expect. The suite keeps representative old saves and confirms the migration logic upgrades them cleanly into the current format. This is what lets me change the game without orphaning everyone who has already played it. A returning player should find their orchard exactly as they left it, and the migration test is the promise that they will.

Sweeping 300 Battle Seeds

The campaign runs on a deterministic seeded simulation. You arrange five cards, and the same seed always produces the exact same fight, every time, on every machine. That property is the foundation of the whole battle system, and it is also what makes the battle system testable at all.

The suite sweeps 300 different seeds through the battle simulation and checks that every one runs to a clean finish. With eight combat keywords and six tribal synergies interacting, the space of possible fights is large, and a bad interaction between two keywords might only surface on a specific seed with a specific card arrangement. Sweeping 300 seeds is how I flush those out. A keyword change that breaks an edge case trips one of those seeds, and I find it before I ship, not when a player hits the exact combination that crashes.

Determinism is doing the heavy lifting here. A game that uses raw randomness is fundamentally hard to test, because you cannot reproduce a failure. The fight that broke ran once and is gone. By seeding every fight, the same input always gives the same output, which makes a failing seed a permanent, reproducible test case. Determinism is not a nice-to-have for the campaign. It is the property that converts an untestable system into a testable one.

Enumerating The Slot Machine's Exact Odds

The slot machine is an economy, and an economy with wrong numbers is a broken game. So the suite does not estimate the slot odds, it enumerates them exactly.

Rather than spinning the machine a few thousand times and measuring roughly how often it pays out, the suite walks through every possible combination the reels can produce and counts the winning ones directly. That gives the exact expected value as arithmetic, not a sample that got close. This is how I know the per-row win probability is precisely 11.3 percent at three reels, 31.5 percent at four, and 56.1 percent at five. If I ever change a reel layout or a tier weight and break the intended odds, the test catches it immediately, because the computed expected value stops matching what I designed. The economy is checked by exhaustion, not by sampling, and that is the only way I would trust numbers a player's whole experience depends on.

Per-System Regression And The Confidence To Refactor

On top of the headline checks, the suite runs per-system regression tests, focused assertions on the orchard's vitality decay, the Lab's essence math, the breeding tier-up odds, the museum's multipliers, and the rest. Each one pins down a specific behavior so that when I change one system, the suite tells me whether I quietly broke another.

That last point is the entire payoff, and it is the thing I would tell any solo developer. The real gift of a test suite is not the bugs it catches, it is the fear it removes. Without it, every refactor is terrifying, because the game has six systems that touch each other and you cannot hold all the interactions in your head. So you stop refactoring, you build around the messy code instead of cleaning it up, and the project rots. With a smoke suite that instances every scene, round trips every save, sweeps 300 battle seeds, and enumerates the exact economy, I can tear into a system and trust that the suite will scream if I broke something three systems away. That confidence is what lets one person keep a game with this much surface area healthy, and it is the reason I can still move fast.

Play The Thing The Tests Protect

Every system I described above is covered by that suite, which is why the game holds together end to end despite being built by one pair of hands.

Play Orchard Deck in your browser

If you want the wider story of how it all came together, there is an overview of building Orchard Deck. And there is a feedback button right on the game page. A test suite catches the bugs I can imagine, but players find the ones I never thought to write a test for, so if something breaks on you, tell me, and the next thing I do is write the test that should have caught it.

Built by Kevin

Like this? You'll like what I'm building too.

Two ways to support and get more of this work.

Desktop App

HEARTH

A privacy-first Life OS for your desktop. Journal, tasks, and notes that stay on your machine. Coming soon, direct download from this site.

Read more
Digital Products

MY TOOLKITS

Receipts-first toolkits for shipping after hours, building Claude agents, publishing on Amazon, and more. The exact methods I used, not theory.

Browse on Whop

Need This Built?

Kevin builds products solo, from first version to live. If you want something like this made, work with him.