Overview

2 Idioms and testing

This chapter adopts a testing-first mindset while introducing idiomatic Go design through a small url package. It begins with a minimal implementation of parsing and printing URLs, then iteratively strengthens both the code and tests, using failures to guide improvements. The overarching theme is that clear, simple APIs, explicit error handling, and alignment with the standard library make programs easier to maintain and verify.

The idioms emphasized include choosing concise, non-stuttering package and identifier names; preferring short variable names in narrow scopes; returning errors as ordinary, last results; and exporting struct fields when you don’t need encapsulation or immutability (avoiding premature getters/setters). Behavior belongs on methods such as String, and types should satisfy standard interfaces like fmt.Stringer so they compose naturally with existing packages. The chapter also discusses when to use pointer receivers, and the trade-offs around mutability, performance, and clarity.

On testing, it shows how to write and run tests with go test and the testing package, covering file and function naming conventions, the roles of Errorf versus Fatalf, and clear “got/want” failure messages. It replaces duplicated checks with table-driven tests, then restores isolation and debuggability by converting each table row into a subtest, enabling selective runs and preventing one failure from halting the rest; options like shuffling, caching, and failfast are demonstrated. The url example evolves via failing tests to handle cases such as missing schemes and opaque data URLs, and the chapter closes with example tests that double as runnable documentation, setting the stage for coverage, benchmarking, and optimization next.

The url package's overview. Parse returns a pointer to a URL value that contains the parsed URL's parts. String reassembles the URL value as a string.
The go test tool and the testing package collaborate in running tests. Tests get a *T, which has methods for tests to call, to log, report failures, etc.
The Cut function cuts a string, returning segments before and after the separator. The found result value indicates the detection of the separator.
Using the same test logic when testing with various data.
Illustration of mapping a table of test cases to a slice of struct values.
Skips the other case because of a fatal failure while running the first.
Running test cases within the same test vs. in separate subtests.
Test runs two subtests, each running a test case in a new goroutine.
The Parse function's documentation provides an interactive example.

Summary

  • Commenting on package items generates documentation automatically.
  • Capitalizing the first letter of a package item exports it from its package.
  • Go can automatically dereference a pointer type to a value type.
  • Exporting allows other packages to access the items in the exporter package.
  • Return an error result as the last result value if a function is expected to fail.
  • Errors are ordinary values that are a part of the normal code flow, not exceptions.
  • The errors.New function returns a new non-nil error value.
  • Returning a nil error indicates success. A non-nil error often indicates a failure.
  • A package's name should concisely communicate what it provides. The package name should be meaningful when combined with its exported items.
  • Avoid stuttering package items with their package names for clarity.
  • Avoid unnecessarily unexporting struct fields.
  • Be generous when exporting struct fields to provide direct access. Otherwise, unexport them to provide immutability or implement business logic.
  • Implement the standard library interfaces to be more effective.
  • The Stringer interface has a single String method that returns a string.
  • Functions like Println can automatically call the String method.
  • Interfaces wrap values by copying them, whether the values are pointers or not.
  • When an interface wraps a value type, we can no longer use the type's pointer receiver methods through the interface due to copying.
  • The any type is an empty interface without methods that any type can satisfy.
  • Avoid mixing receiver types for a type to prevent surprising behavior.
  • The go test tool runs tests from the command line.
    • The run flag allows us to execute specific tests by name.
    • The verbose flag allows us to see verbose output from tests.
    • The shuffle flag allows us to shuffle the running of test functions.
    • The failfast flag allows us to stop a test run after the first failing test.
  • The testing package provides functionality for writing tests.
  • A package can have zero or more test files.
  • Test files have a _test.go suffix.
  • Test functions have a Test prefix and take a *T.
  • It's idiomatic to name tests after what they test.
  • Dereferencing a nil pointer would cause a panic (runtime crash).
  • T.Errorf and T.Fatalf make tests fail, and the latter also stops the test's run.
  • T.Errorf helps us see the whole picture without rerunning tests.
  • T.Errorf automatically calls the String method when we use the %s verb.
  • T.Errorf with the %#v verb prints the Go syntax of a given value.
  • Descriptive failure messages help us quickly identify the reasons for the failure.
  • Structs can be compared if their fields consist of comparable types.
  • Use the go-cmp package when comparing complex values.
  • The compiler excludes the test code when we build with go build or go run.
  • Use named return values for readability, but be careful with aliasing issues.
  • Table-driven tests simplify adding test cases without having to repeat the test logic.
  • Subtests are standalone test functions run by another test function. When combined with table-driven tests, subtests help empower us to write more resilient tests.
    • Similar to ordinary test functions, subtests run in a separate goroutine.
    • A test function can run a subtest using *T's Run method.
    • Subtests can fail with a fatal failure without stopping others.
    • Combining subtests with table-driven tests is powerful for resilient testing.
  • Sharing *testing.T among different tests can lead to surprising results.
  • Example tests both verify code and provide interactive code examples.
    • They have an Example prefix and don't require any input parameters.
    • The Output comment determines the expected output of an example test.
  • Test packages are named after the package they test, enabling black-box testing.

FAQ

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Go by Example ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Go by Example ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Go by Example ebook for free