liveBook · Manning

Test

As explained in Shipping Go: Develop, deliver, discuss, design, and go again

A test case is a defined set of inputs, conditions, and expected results for evaluating software behavior.

A release can look ready while leaving QA to rediscover familiar bugs. Testing moves some of that work earlier: define what the software should do, check it automatically, and use failures to guide the next small change. A test case pairs an input or condition with an expected result; together, cases record business expectations as well as catch regressions. section 3.0 section 1.3.2

Start by sketching use cases with a teammate. Then choose a system under test with a clear boundary and check its inputs and outputs rather than its internal steps. A translation API, for example, can be split into a translation service, an HTTP handler, and a server. Smaller boundaries make failures easier to locate. section 3.1 section 3.8

For a translation service, useful cases include:

  • Given “hello” and English, return “hello”; given German or Finnish, return “hallo” or “hei.” section 3.3
  • Given an unsupported language or a word with no translation, return an empty string. section 3.3
  • Given capitalization or extra spaces in the input, return the same translation as for normalized input. section 3.3

Write a case, run it, and let a failure identify the behavior to implement. Once it passes, keep the test while refactoring: it protects the requirement even if the implementation changes. Before changing an expectation to make a test pass, consider whether the business requirement has changed. Test negative paths and edge cases, not only successful requests. section 3.3

Listing 3.5 translator_test.go
package translate_test
 
import (
    "testing"
    "github.com/holmes89/hello-api/translation"
)
 
func TestTranslate(t *testing.T) {
    res := translation.Translate("hello", "english")            #1
    if res != "hello" {
        t.Errorf(`expected "hello" but recieved "%s"`, res)
    }
 
    res = translation.Translate("hello", "german")              #2
    if res != "hallo" {
        t.Errorf(`expected "hallo" but recieved "%s"`, res)
    }
 
    res = translation.Translate("hello", "finnish")             #3
    if res != "hei" {
        t.Errorf(`expected "hei" but received "%s"`, res)
    }
 
    res = translation.Translate("hello", "dutch")               #4
    if res != "" {
        t.Errorf(`expected "" but received "%s"`, res)
    }
 
}

A Go test checks several language inputs and reports the expected and actual translation when a case fails. section 3.3

Run fast unit tests as a quality gate before the build. The example CI job runs `go test ./...`, and the build waits for that job. Coverage reports can point to untested branches, but a high percentage cannot prove that behavior matches customer expectations; use coverage to guide additions and refactoring, not as a substitute for meaningful cases. section 3.6 section 3.7

Grow the checks with the product. Unit tests establish a foundation; isolated tests can use injected dependencies, stubs, and mocks, while integration tests check larger services. Acceptance cases ask whether a customer-facing rule holds—for example, whether an insufficient balance produces an error. Broader end-to-end checks assess the whole system but cost more to run and maintain, so begin with core behavior and expand where bugs reveal risk. section 6.0 section 1.3.8 section 1.3.10 section 11.4.2

How Shipping Go: Develop, deliver, discuss, design, and go again covers it

How deep it goes
Works through selecting boundaries, writing translation cases, running tests, and checking coverage; defers full-system end-to-end UI-to-API testing.
Examples
Uses a Go translation service with expected outputs, unsupported inputs, capitalization, whitespace, and a CI test job.
What it assumes
Assumes familiarity with code and functions while teaching how to choose test cases and establish testable boundaries.
What you can do after
Practice/perform writing behavior-focused cases and running them as an automated quality gate before building.
How it connects
Connects testing to systems under test, unit tests, mocking, integration tests, acceptance testing, code coverage, and continuous integration.

Also explained in

Compare how 53 books explain test →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Shipping Go: Develop, deliver, discuss, design, and go again. The section links point to the parts of the book it draws on.