- Introduction
- Setting Up GoLand
- Running Tests in GoLand
- TDD Workflow in GoLand
- Productivity Features
- Debugging Tests
- Code Coverage
- Live Templates for Testing
- Keyboard Shortcuts
- Tips and Best Practices
JetBrains GoLand is a powerful IDE specifically designed for Go development. It has excellent built-in support for testing and TDD workflows, making it an ideal choice for practicing Test-Driven Development.
- Integrated test runner with visual feedback
- Code generation for tests
- Live code coverage visualization
- Powerful refactoring tools
- Smart code completion in tests
- Quick navigation between tests and implementation
- Built-in debugger for tests
-
Download GoLand:
- Visit jetbrains.com/go
- Download for your OS (Windows, macOS, Linux)
- 30-day free trial available
-
Install Go SDK:
- GoLand will detect Go installation automatically
- If not:
File → Settings → Go → GOROOT - Verify: Check Go version in status bar
-
Open Your Project:
File → Open→ Select your project directory- GoLand will automatically detect
go.mod - Wait for indexing to complete
Enable Auto-Import:
File → Settings → Editor → General → Auto Import
☑ Show import popup
☑ Add unambiguous imports on the fly
Configure Test Runner:
File → Settings → Go → Test Runner
☑ Enable test runner
☑ Auto-scroll to source
Test output: Show passed tests
Enable File Watchers (Optional):
File → Settings → Tools → File Watchers
Add → Go fmt (formats code on save)
Look for the green play icon next to:
- Individual test functions
- Test files
- Packages
Click the icon to:
- Run (green play) - Run tests
- Debug (green bug) - Debug tests
- Run with Coverage (play with shield)
func TestAdd(t *testing.T) { // ▶️ Green icon appears here
result := Add(2, 3)
expected := 5
if result != expected {
t.Errorf("Add(2, 3) = %d; want %d", result, expected)
}
}Right-click anywhere in the file:
Run 'TestAdd'- Run single testRun 'calculator_test.go'- Run all tests in fileRun 'All Tests'- Run all tests in project
Run tests:
Ctrl+Shift+F10(Windows/Linux) orCtrl+Shift+R(macOS)- Runs the test at cursor position
Rerun last test:
Shift+F10(Windows/Linux) orCtrl+R(macOS)
Run with coverage:
Ctrl+Shift+F10then select "Run with Coverage"
Create a permanent run configuration:
Run → Edit Configurations- Click
+→Go Test - Configure:
Name: All Tests Test kind: Directory Directory: ./... Pattern: .* - Click
OK
Now you can run from the toolbar dropdown!
Step 1: Create test file
Right-click package → New → Go File
Name: calculator_test.go
Step 2: Write test
package calculator
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3) // ⚠️ Red underline - Add() doesn't exist
expected := 5
if result != expected {
t.Errorf("Add(2, 3) = %d; want %d", result, expected)
}
}Step 3: Run test (it fails)
- Click green play icon → Red X appears
- Test output shows:
undefined: Add
Quick Fix to Generate Function:
- Place cursor on
Add(2, 3) - Press
Alt+Enter(Windows/Linux) orOption+Enter(macOS) - Select
Create function 'Add' - GoLand generates:
func Add(i int, i2 int) int {
//TODO implement me
panic("implement me")
}Implement the function:
func Add(a, b int) int {
return a + b
}Run test again:
- Click green play icon → Green checkmark!
- Test output shows:
PASS
Use GoLand's refactoring tools:
-
Rename -
Shift+F6- Rename variables, functions, parameters
- All references updated automatically
-
Extract Method -
Ctrl+Alt+M(Windows/Linux) orCmd+Alt+M(macOS)- Select code → Extract to new function
-
Inline -
Ctrl+Alt+N(Windows/Linux) orCmd+Alt+N(macOS)- Inline function or variable
Run tests after each refactor to ensure they still pass!
Automatically generate test stubs:
- Place cursor on function name
- Press
Ctrl+Shift+T(Windows/Linux) orCmd+Shift+T(macOS) - Select
Create New Test - Choose:
- Test file name
- Test function name
- Testing framework
Example: For function Divide, GoLand generates:
func TestDivide(t *testing.T) {
type args struct {
a int
b int
}
tests := []struct {
name string
args args
want float64
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Divide(tt.args.a, tt.args.b)
if (err != nil) != tt.wantErr {
t.Errorf("Divide() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("Divide() got = %v, want %v", got, tt.want)
}
})
}
}Quick navigation:
Ctrl+Shift+T(Windows/Linux) orCmd+Shift+T(macOS)- Toggles between
calculator.go↔calculator_test.go
Navigate to related symbol:
Ctrl+Alt+Home- Go to related files- Shows all files related to current file
IntelliSense in tests:
func TestAccount(t *testing.T) {
account := NewAccount("John", 100.0)
account. // ← Type dot, get all methods
// GoLand shows: Deposit, Withdraw, GetBalance, Transfer
}Completion for testing package:
t. // ← Shows all testing.T methods
// Error, Errorf, Fatal, Fatalf, Helper, Run, etc.Built-in test templates:
Type abbreviation + Tab:
test - Basic test function:
func TestName(t *testing.T) {
}testt - Table-driven test:
func TestName(t *testing.T) {
tests := []struct {
name string
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
})
}
}bench - Benchmark test:
func BenchmarkName(b *testing.B) {
for i := 0; i < b.N; i++ {
}
}Alt+Enter magic:
result := Add(2, 3) // ← Alt+Enter on undefined function
// Options:
// - Create function 'Add'
// - Create method 'Add'
// - Import package
if err != nil { // ← Alt+Enter here
// Options:
// - Add return statement
// - Add log statement
}- Click left gutter next to line number
- Red dot appears - breakpoint set
- Right-click breakpoint for conditions
Start debugging:
- Click debug icon (green bug) next to test
- Or:
Ctrl+Shift+F9(Windows/Linux) orCtrl+Shift+D(macOS)
Debug panel shows:
- Variables - Current values
- Watches - Custom expressions
- Call Stack - Function call hierarchy
- Console - Test output
F8 - Step Over
F7 - Step Into
Shift+F8 - Step Out
F9 - Resume Program
Ctrl+F8 - Toggle Breakpoint
func TestWithdraw(t *testing.T) {
account := NewAccount("John", 100.0) // ← Set breakpoint here
err := account.Withdraw(50.0)
if err != nil { // ← Set breakpoint here
t.Errorf("Unexpected error: %v", err)
}
}During debug:
- Inspect
account.Balancevalue - Check
errvalue - Step through
Withdrawfunction
Method 1: Run icon
- Right-click green play icon
- Select
Run 'TestName' with Coverage
Method 2: Keyboard
Ctrl+Shift+F10then select coverage option
Method 3: Menu
Run → Run 'TestName' with Coverage
Green/Red highlighting:
- Green - Code is covered by tests
- Red - Code is NOT covered by tests
- Yellow - Code is partially covered
Example:
func Divide(a, b int) (float64, error) {
if b == 0 { // ✓ Green - tested
return 0, fmt.Errorf("division by zero")
}
return float64(a) / float64(b), nil // ✗ Red - not tested
}View detailed coverage:
Run → Show Code Coverage Data- Shows percentage per file/package
- Click to navigate to uncovered code
Coverage settings:
Run → Edit Configurations → Coverage tab
☑ Track per test coverage
☑ Enable coverage in test runner
Run → Generate Coverage Report
Choose format: HTML, XML, or Plain Text
Settings → Editor → Live Templates → Go
Example: Create "terr" template
- Click
+→ Live Template - Abbreviation:
terr - Template text:
if err != nil {
t.Errorf("Unexpected error: %v", err)
}- Define applicable contexts: Go → Statement
Now type terr + Tab in any test!
Table-driven test with error:
// Abbreviation: testte
tests := []struct {
name string
input $INPUT_TYPE$
expected $EXPECTED_TYPE$
expectError bool
}{
{$FIRST_CASE$},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := $FUNC$(tt.input)
if tt.expectError && err == nil {
t.Error("Expected error but got none")
}
if !tt.expectError && err != nil {
t.Errorf("Unexpected error: %v", err)
}
if result != tt.expected {
t.Errorf("got %v; want %v", result, tt.expected)
}
})
}Mock struct:
// Abbreviation: mock
type Mock$NAME$ struct {
$FIELDS$
}
func (m *Mock$NAME$) $METHOD$($PARAMS$) $RETURNS$ {
$END$
}| Action | Windows/Linux | macOS |
|---|---|---|
| Running Tests | ||
| Run test at cursor | Ctrl+Shift+F10 |
Ctrl+Shift+R |
| Rerun last test | Shift+F10 |
Ctrl+R |
| Run with coverage | Ctrl+Shift+F10 → Coverage |
Same |
| Stop running test | Ctrl+F2 |
Cmd+F2 |
| Navigation | ||
| Go to test/implementation | Ctrl+Shift+T |
Cmd+Shift+T |
| Go to declaration | Ctrl+B |
Cmd+B |
| Find usages | Alt+F7 |
Option+F7 |
| Recent files | Ctrl+E |
Cmd+E |
| Editing | ||
| Generate code | Alt+Insert |
Cmd+N |
| Quick fix | Alt+Enter |
Option+Enter |
| Complete code | Ctrl+Space |
Ctrl+Space |
| Refactoring | ||
| Rename | Shift+F6 |
Shift+F6 |
| Extract method | Ctrl+Alt+M |
Cmd+Alt+M |
| Inline | Ctrl+Alt+N |
Cmd+Alt+N |
| Debugging | ||
| Debug test | Ctrl+Shift+F9 |
Ctrl+Shift+D |
| Toggle breakpoint | Ctrl+F8 |
Cmd+F8 |
| Step over | F8 |
F8 |
| Step into | F7 |
F7 |
Create your own shortcuts:
File → Settings → Keymap- Search for action
- Right-click → Add Keyboard Shortcut
- Press your desired combination
Enable persistent test runner:
View → Tool Windows → Run
Pin the window (pin icon)
Benefits:
- See all test results at a glance
- Quickly rerun failed tests
- Filter tests by status (passed/failed)
Project structure view:
Alt+1- Toggle Project view- Tests appear under their packages
- Group by test kind
func TestNewFeature(t *testing.T) {
// TODO: Add more test cases
// TODO: Test edge cases
}View all TODOs:
View → Tool Windows → TODO- Click to navigate
View docs without leaving editor:
Ctrl+Q(Windows/Linux) orF1(macOS)- Shows function documentation in popup
View test and implementation side-by-side:
- Right-click editor tab
- Select
Split RightorSplit Down - Navigate to related file in other pane
- Run tests while viewing implementation
Create scratch files:
Ctrl+Alt+Shift+Insert→ Go Scratch- Test ideas without creating files
- Not saved to project
Commit tests with implementation:
Ctrl+K- Commit- Review changes in diff view
- Ensure tests pass before commit
File Watchers (Advanced):
File → Settings → Tools → File Watchers
Add custom watcher:
File type: Go files
Program: go
Arguments: test $FileDir$
-
Create test file (if needed)
- Right-click package → New → Go File
-
Write failing test
- Use
testlive template - Run test (should fail)
- Use
-
Generate function stub
Alt+Enteron undefined function- Select "Create function"
-
Implement function
- Write minimal code
- Run test (should pass)
-
Refactor
- Use refactoring shortcuts
- Run tests after each change
-
Check coverage
- Run with coverage
- Add tests for uncovered code
-
Write test that reproduces bug
- Test should fail
-
Debug test
- Set breakpoints
- Inspect variables
- Find root cause
-
Fix implementation
- Modify code
- Run test (should pass)
-
Run all tests
- Ensure no regressions
-
Ensure all tests pass
- Run all tests first
-
Make refactoring
- Use IDE refactoring tools
- Rename, extract, inline, etc.
-
Run tests continuously
- After each small change
- If tests fail, undo and try differently
-
Check coverage
- Ensure coverage hasn't decreased
Check GOROOT:
File → Settings → Go → GOROOT
Verify correct Go SDK is selected
Re-index project:
File → Invalidate Caches / Restart
Check test file naming:
- Must end with
_test.go - Must be in same package
Check function naming:
- Must start with
Test - Must have signature
func TestXxx(t *testing.T)
Enable coverage:
Run → Edit Configurations → Coverage tab
☑ Enable coverage
Clear coverage:
Run → Clear All Code Coverage Data
Run specific tests:
- Don't run all tests every time
- Use focused test runs
Disable file watchers:
File → Settings → Tools → File Watchers
Uncheck watchers if too slow
Run tests on remote machine:
Tools → Deployment → Configuration
Add remote server
Map local to remote paths
Built-in database tools:
View → Tool Windows → Database
Connect to test database
Verify test data
Built-in HTTP client:
Tools → HTTP Client → Test RESTful Web Service
Test API endpoints
Save requests for reuse
Run benchmarks:
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(2, 3)
}
}Right-click → Run with Benchmarks
GoLand makes TDD in Go incredibly productive with:
✅ Integrated test runner - Instant feedback ✅ Smart code generation - Less typing ✅ Visual coverage - See what's tested ✅ Powerful refactoring - Change with confidence ✅ Debugging tools - Fix issues quickly
Master these three things:
- Run tests frequently (keyboard shortcuts!)
- Use quick fixes for code generation
- Refactor fearlessly with IDE tools
Happy TDD with GoLand! 🚀