Backend Development 12 min read

Testing Pyramid and Integration Testing Practices for a Go Service

By applying Mike Cohn’s testing pyramid to a Go scheduling service, the author demonstrates a structured approach that combines straightforward unit tests, organized integration suites with setup/teardown hooks and coverage scripts, expressive GoConvey assertions, and end‑to‑end trace‑ID verification, while noting remaining gaps.

Didi Tech
Didi Tech
Didi Tech
Testing Pyramid and Integration Testing Practices for a Go Service

The author shares recent practice on testing a project that involves four services, with a core scheduling service, and discusses how to ensure output quality through a structured testing approach.

Testing Pyramid

According to Mike Cohn's "Testing Pyramid" concept, testing is divided into four layers:

Unit tests – test individual functions or classes.

Integration tests – test a service's interfaces.

End‑to‑end (link) tests – test the whole request flow across services.

UI tests – test functionality through the user interface.

Unit Testing

For a Go service, unit testing is straightforward: create a *_test.go file next to the source file and run go test . The primary metric is code coverage.

Integration Testing

Thoughts and Requirements

The goal is to automate integration tests for the HTTP APIs of the scheduling service, run all cases with a single command, and measure coverage (focused on the controller layer). The author adopts JUnit‑like concepts: TestCase (individual test) and TestSuite (a collection of related tests) with SetUp , Before , TearDown , and After hooks.

Implementation

A dedicated suites directory holds test suites. Each suite contains:

before.go – defines SetUp() and Before() .

after.go – defines TearDown() and After() .

run_test.go – the entry point for the suite.

package adapt

import "testing"
import . "github.com/smartystreets/goconvey/convey"

func TestRunSuite(t *testing.T) {
    SetUp()
    defer TearDown()
    Convey("初始化", t, nil)
    runCase(t, NormalCasePEE001)
    runCase(t, PENormalCase01)
    // ... other cases ...
    runCase(t, NormalCase07)
    runCase(t, NormalCase08)
    runCase(t, NormalCasePIN003)
    runCase(t, NormalCasePIN005)
    runCase(t, NormalCasePIN006)
    runCase(t, NormalCasePIN015)
}

func runCase(t *testing.T, testCase func(*testing.T)) {
    Before()
    defer After()
    testCase(t)
}

Test Case Writing

Test cases use the standard httptest package to send HTTP requests. No special handling is required.

Coverage

A shell script is used to generate coverage limited to the controller layer:

#!/bin/bash

go test -coverpkg xxx/controllers/... -coverprofile=report/coverage.out ./...

go tool cover -html=report/coverage.out -o report/coverage.html

open report/coverage.html

Introducing GoConvey

GoConvey provides a web UI, an editor for test cases, and live re‑run on file changes. It also offers expressive assertions:

package package_name
import (
    "testing"
    . "github.com/smartystreets/goconvey/convey"
)

func TestIntegerStuff(t *testing.T) {
    Convey("Given some integer with a starting value", t, func() {
        x := 1
        Convey("When the integer is incremented", func() {
            x++
            Convey("The value should be greater by one", func() {
                So(x, ShouldEqual, 2)
            })
        })
    })
}

The web UI shows failing cases and assertions clearly, and automatically re‑runs tests when source files change.

End‑to‑End Testing

End‑to‑end testing validates the full request flow across multiple services, possibly written in different languages. The author suggests using a trace ID passed via HTTP headers and a centralized log monitoring system to verify that each service logs the expected tags.

UI Testing

Currently performed manually by testers clicking through the UI, which is common in many companies.

Summary

The author reflects on several weeks of integration‑testing practice, acknowledges remaining gaps, and encourages adopting all four layers of the testing pyramid for complex, critical business logic.

TestingGounit testingintegration-testingCoveragegoconveytest pyramid
Didi Tech
Written by

Didi Tech

Official Didi technology account

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.