GoLand test debugging with Delve: logpoints, race detection, and avoiding fmt clutter
Debug failing Go tests directly in GoLand using Delve-based breakpoints, logpoints, and the race detector instead of scattered fmt.Println statements.
17 Aug 2026, 21:29 UTC

Why fmt.Println still shows up in Go test debugging
When a Go test fails, it’s tempting to reach for fmt.Println. The output appears in the test log, you glance at values, and you move on. The problem is that every print statement is dead code waiting to happen: you forget to remove it, the next developer does the same, and the binary size creeps up. fmt calls also don’t help with data races — Go’s race detector needs instrumented binaries, not ad-hoc prints.
GoLand’s Delve-powered test debugger
GoLand integrates the Delve debugger, so you can set breakpoints and step through go test runs without leaving the IDE. The gutter icon next to a test function lets you run or debug a single test, a whole file, or an entire package. Click the bug icon instead of the play button, and the debugger stops at your breakpoint, showing local variables, map entries, and channel state in the right-hand sidebar.
Running a single test
- Place the cursor inside or on a test function.
- Click the gutter
🔴icon that appears to the left of the line numbers. - Select Debug from the context menu.
- The Debug tool window opens, Delve loads the test binary, and execution stops at the breakpoint.
Inspecting goroutines
Concurrency bugs in Go often stem from goroutine scheduling or channel blocking. The debugger includes a Goroutines view that lists all active goroutines, their stacks, and current channels. This is valuable when a test hangs or deadlocks — you can see which goroutine holds which lock and whether a select statement is starved.
Logpoints: printing without stopping
Conditional breakpoints stop every iteration, which can drown you in noise when debugging a loop that runs thousands of times. A logpoint is a non-suspending breakpoint that prints a message to the console and continues execution. It’s ideal for watching a variable’s value over many iterations without breaking the test flow.
How to set a logpoint
- Right-click the gutter margin next to a line and choose More Breakpoint Options….
- Disable the Suspend checkbox and set the Expression to the variable or expression you want to surface.
- Click OK. The gutter icon changes to a diamond shape, indicating a logpoint.
- Run the test in debug mode. Each time the line executes, the value appears in the console without pausing execution.
The race detector: a practical engineering decision
Data races are among the hardest bugs to track down in Go. The race detector, invoked with the -race flag, instruments the runtime to detect conflicting memory accesses across goroutines. GoLand’s run configuration lets you add this flag once, and every test run in the IDE mirrors the behavior of go test -race from the terminal.
Configuring -race in GoLand
- Open Run > Edit Configurations….
- Select your test configuration (or create a new Go Test configuration).
- In the Additional arguments field, add -race.
- Apply and run a test. The test output will include race detection reports if a data race is found.
To verify parity, run the same test from the terminal (no elevated privileges required):
go test -race ./...
Compare the race report output between GoLand and the terminal. If both show the same data-race stack traces, the IDE configuration matches CI behavior.
Trade-offs and limitations
While GoLand’s debugger is powerful, it isn’t without caveats. Delve’s expression evaluator may struggle with very recent Go language features, especially generics or runtime-internal types, and not every valid expression evaluates correctly at a breakpoint. Debugging optimized binaries can also be misleading — variables may be inlined or elided, making the watch pane appear empty even when the code is correct. Additionally, the bundled Delve version in older GoLand releases might not support the Go toolchain installed on your machine; checking GoLand About Delve version against go version is a quick sanity check.
Actionable next steps
- Identify a failing test that currently uses fmt.Println for value tracing.
- Replace the prints with a logpoint in GoLand — right-click the gutter, configure the expression, and run in debug mode.
- Add -race to the test’s run configuration and run the test twice: once in GoLand, once from the terminal, to confirm the race-detector output is consistent.
- If the test involves concurrency, open the Goroutines view to inspect stack traces and channel states.
- Review the trade-offs above and decide whether the cleaner workflow justifies the occasional need to fall back to terminal-based debugging.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.