End-to-end testing is testing the entire system from API to DB.
1// Integration test with real DB2func TestUserAPI(t *testing.T) {3 if testing.Short() {4 t.Skip("Skipping integration test")5 }67 // Setup8 db := setupTestDB(t)9 defer db.Close()1011 server := NewServer(db)12 ts := httptest.NewServer(server)13 defer ts.Close()1415 // Test creating a user16 t.Run("create user", func(t *testing.T) {17 payload := `{"name":"Alice","email":"alice@example.com"}`18 resp, err := http.Post(19 ts.URL+"/api/users",20 "application/json",21 strings.NewReader(payload),22 )23 if err != nil {24 t.Fatal(err)25 }26 defer resp.Body.Close()2728 if resp.StatusCode != http.StatusCreated {29 t.Errorf("expected 201, got %d", resp.StatusCode)30 }3132 var user User33 json.NewDecoder(resp.Body).Decode(&user)34 if user.Name != "Alice" {35 t.Errorf("expected Alice, got %s", user.Name)36 }37 })3839 // Test getting a user40 t.Run("get user", func(t *testing.T) {41 resp, err := http.Get(ts.URL + "/api/users/1")42 if err != nil {43 t.Fatal(err)44 }45 defer resp.Body.Close()4647 if resp.StatusCode != http.StatusOK {48 t.Errorf("expected 200, got %d", resp.StatusCode)49 }50 })51}5253// Test with containers (testcontainers)54func TestWithContainer(t *testing.T) {55 ctx := context.Background()5657 req := testcontainers.ContainerRequest{58 Image: "postgres:15",59 ExposedPorts: []string{"5432/tcp"},60 Env: map[string]string{61 "POSTGRES_DB": "testdb",62 "POSTGRES_USER": "test",63 "POSTGRES_PASSWORD": "test",64 },65 WaitingFor: wait.ForListeningPort("5432/tcp"),66 }6768 container, err := testcontainers.GenericContainer(ctx,69 testcontainers.GenericContainerRequest{70 ContainerRequest: req,71 Started: true,72 },73 )74 if err != nil {75 t.Fatal(err)76 }77 defer container.Terminate(ctx)7879 host, _ := container.Host(ctx)80 port, _ := container.MappedPort(ctx, "5432")8182 dsn := fmt.Sprintf("postgres://test:test@%s:%s/testdb?sslmode=disable",83 host, port.Port())8485 db, _ := sql.Open("postgres", dsn)86 defer db.Close()8788 // Tests with real DB...89}9091// BDD style with godog92func FeatureContext(s *godog.Suite) {93 s.Step(`^I have a user with name "([^"]*)"$`, iHaveAUserWithName)94 s.Step(`^I should see the user$`, iShouldSeeTheUser)95}9697func iHaveAUserWithName(name string) error {98 _, err := db.CreateUser(&User{Name: name})99 return err100}101102func iShouldSeeTheUser() error {103 user, err := db.GetUser(1)104 if err != nil {105 return err106 }107 if user == nil {108 return errors.New("user not found")109 }110 return nil111}
Strategies: