Welcome to your first Go adventure! 🎉
Today, we’re tackling the classic “Hello, World” program—but with tests.
Because we’re fancy like that.
Step 1: The Basics
Create a Simple Go Program
- Make a folder (anywhere you like).
- Add a file called
hello.go
with this code:
package main
import "fmt"
func main() {
fmt.Println("Hello, world")
}
Run it with:
go run hello.go
Boom! You just printed “Hello, world” like it’s 1974.
How It Works
package main
→ Your program’s starting point.import "fmt"
→ Brings in Go’s printing magic.func main()
→ Where the fun begins.
Step 2: Let’s Test This Thing
Printing is cool, but tests are cooler. Let’s make our code testable by separating logic from side effects (like printing).
Refactor for Testability
Update hello.go
:
package main
import "fmt"
func Hello() string {
return "Hello, world"
}
func main() {
fmt.Println(Hello())
}
Now, create hello_test.go
:
package main
import "testing"
func TestHello(t *testing.T) {
got := Hello()
want := "Hello, world"
if got != want {
t.Errorf("got %q, want %q", got, want)
}
}
Run the test:
go test
✅ Success! (Unless you broke it on purpose. You rebel.)
Wait… Go Modules?
If you’re on Go 1.16+, you might see:
go: cannot find main module; see 'go help modules'
Fix it with:
go mod init example.com/hello
This creates a go.mod
file. Now go test
should work!
Step 3: Make It Personal
Let’s greet people by name. Test first!
func TestHello(t *testing.T) {
got := Hello("Chris")
want := "Hello, Chris"
if got != want {
t.Errorf("got %q, want %q", got, want)
}
}
The compiler yells at you (helpfully):
./hello_test.go:6:18: too many arguments in call to Hello
Update the Function
func Hello(name string) string {
return "Hello, " + name
}
Run tests again. Green light! 🚦
Step 4: Handle Empty Names
What if someone doesn’t give a name? Default to “World”.
Test It
t.Run("empty string defaults to 'world'", func(t *testing.T) {
got := Hello("")
want := "Hello, World"
assertCorrectMessage(t, got, want)
})
Implement It
func Hello(name string) string {
if name == "" {
name = "World"
}
return "Hello, " + name
}
Step 5: Multilingual Greetings
Now let’s say hello in Spanish! 🌍
Test First
t.Run("in Spanish", func(t *testing.T) {
got := Hello("Elodie", "Spanish")
want := "Hola, Elodie"
assertCorrectMessage(t, got, want)
})
Update the Function
func Hello(name, language string) string {
if name == "" {
name = "World"
}
switch language {
case "Spanish":
return "Hola, " + name
default:
return "Hello, " + name
}
}
Bonus: Add French ("Bonjour"
) or any language you want!
Step 6: Refactor Like a Pro
Clean up magic strings with constants:
const (
spanish = "Spanish"
french = "French"
englishPrefix = "Hello, "
spanishPrefix = "Hola, "
frenchPrefix = "Bonjour, "
)
func Hello(name, language string) string {
if name == "" {
name = "World"
}
prefix := englishPrefix
switch language {
case spanish:
prefix = spanishPrefix
case french:
prefix = frenchPrefix
}
return prefix + name
}
Key Takeaways
✅ TDD Workflow:
- Write a failing test.
- Make it pass.
- Refactor.
✅ Go Basics Learned:
- Functions (
func
) - Variables & constants (
:=
,const
) - Conditionals (
if
,switch
) - Testing (
testing
package)
✅ Best Practices:
- Keep logic separate from side effects.
- Use constants for magic strings.
- Write small, focused tests.
Next Up: Integers.