Files
interview/questions/13-Golang语言/go-testing.md
yasinshaw ab3a99f131 feat: add 10 Golang interview questions
Added comprehensive Golang interview preparation materials:
- 基础语法(值类型、切片、map、defer、接口、struct、new/make)
- Goroutine 和并发模型(与线程对比、调度模型、内存模型)
- 错误处理和测试(error、panic/recover、单元测试、Benchmark)
- 并发编程进阶(Mutex、RWMutex、WaitGroup、atomic、数据竞争)
- HTTP 和 Web 开发(Client、Server、中间件模式)
- 内存模型和垃圾回收(内存分配、逃逸分析、GC)
- 性能优化(pprof、内存优化、CPU优化、并发优化)
- 反射和 unsafe(反射性能、unsafe 使用场景)
- 接口和类型系统(类型断言、interface{}、类型嵌入、泛型)
- 数据库操作(database/sql、GORM、事务、SQL 注入防护)
- 项目结构和工程化(标准项目结构、Go Module、CI/CD)

Each file includes:
- Detailed questions and comprehensive answers
- Code examples and best practices
- Alibaba P7 level requirements

Total: 60 interview questions (50 backend + 10 Golang)

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-01 00:16:36 +08:00

409 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Golang 错误处理和测试
## 问题
1. Go 的错误处理机制是什么?为什么不用 try-catch
2. panic 和 recover 的使用场景是什么?
3. errors.Wrap 和 errors.Is 的作用是什么?
4. Go 的单元测试如何写?有哪些最佳实践?
5. table-driven test 是什么?
6. Go 的基准测试Benchmark如何写
---
## 标准答案
### 1. Go 的错误处理
#### **error 接口**
```go
type error interface {
Error() string
}
```
**特点**
- 错误是值,不是异常
- 必须显式处理
- 避免嵌套过深
---
#### **创建错误**
```go
import "errors"
// 1. 简单错误
err1 := errors.New("something went wrong")
// 2. fmt.Errorf
err2 := fmt.Errorf("invalid user: %s", "alice")
// 3. 错误包装Go 1.13+
if err != nil {
return fmt.Errorf("query failed: %w", err)
}
```
---
#### **处理错误**
```go
func readFile(path string) ([]byte, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read file failed: %w", err)
}
return data, nil
}
```
---
### 2. panic 和 recover
#### **panic**
**用途**:不可恢复的错误(程序无法继续运行)
```go
// panic 示例
func doPanic() {
panic("something terrible happened")
}
func main() {
doPanic()
fmt.Println("this will not print")
}
```
---
#### **recover**
**用途**:捕获 panic防止程序崩溃
```go
func safeExecute() {
defer func() {
if err := recover(); err != nil {
fmt.Println("recovered from:", err)
}
}()
panic("oh no!")
}
func main() {
safeExecute()
fmt.Println("program continues")
}
```
---
#### **最佳实践**
1. **避免使用 panic**:除非是真正不可恢复的错误
2. **recover 只在 defer 中使用**:其他地方无效
3. **库代码不应 panic**:应该返回 error
---
### 3. 错误包装和判断
#### **errors.Wrap**
```go
import (
"errors"
"fmt"
)
func queryDB() error {
return errors.New("connection failed")
}
func service() error {
err := queryDB()
if err != nil {
return fmt.Errorf("service failed: %w", err) // 包装错误
}
return nil
}
func main() {
err := service()
if err != nil {
// 检查错误链
if errors.Is(err, errors.New("connection failed")) {
fmt.Println("is connection error")
}
// 获取最底层的错误
var connErr error = errors.New("connection failed")
if errors.Is(err, connErr) {
fmt.Println("connection error occurred")
}
}
}
```
---
#### **自定义错误类型**
```go
import "errors"
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
func validate(name string) error {
if name == "" {
return &ValidationError{Field: "name", Message: "required"}
}
return nil
}
func main() {
err := validate("")
var ve *ValidationError
if errors.As(err, &ve) {
fmt.Println("validation error:", ve.Field, ve.Message)
}
}
```
---
### 4. 单元测试
#### **基本测试**
```go
package mypackage
import "testing"
func Add(a, b int) int {
return a + b
}
func TestAdd(t *testing.T) {
result := Add(1, 2)
if result != 3 {
t.Errorf("Add(1, 2) = %d; want 3", result)
}
}
```
---
#### **Table-Driven Test表格驱动测试**
```go
func TestAddTableDriven(t *testing.T) {
tests := []struct {
a, b int
want int
}{
{1, 2, 3},
{2, 3, 5},
{10, -5, 5},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%d+%d", tt.a, tt.b), func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.want {
t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want)
}
})
}
}
```
---
#### **子测试Subtests**
```go
func TestAll(t *testing.T) {
t.Run("Test1", func(t *testing.T) {
// Test1
})
t.Run("Test2", func(t *testing.T) {
// Test2
})
}
```
---
### 5. 基准测试Benchmark
#### **基本 Benchmark**
```go
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(1, 2)
}
}
```
**运行**
```bash
go test -bench=. -benchmem
```
---
#### **Benchmark 高级用法**
```go
func BenchmarkAddParallel(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Add(1, 2)
}
})
}
func BenchmarkLargeSlice(b *testing.B) {
b.ResetTimer() // 重置计时器
data := make([]int, 1000000)
b.StartTimer()
for i := 0; i < b.N; i++ {
_ = len(data)
}
}
```
---
### 6. Mock 和测试替身
#### **使用接口进行 Mock**
```go
type Database interface {
Query(id int) (string, error)
}
type Service struct {
db Database
}
func (s *Service) GetUser(id int) (string, error) {
return s.db.Query(id)
}
// Mock 实现
type MockDatabase struct {
MockQuery func(id int) (string, error)
}
func (m *MockDatabase) Query(id int) (string, error) {
return m.MockQuery(id)
}
// 测试
func TestService_GetUser(t *testing.T) {
mockDB := &MockDatabase{
MockQuery: func(id int) (string, error) {
return "Alice", nil
},
}
service := &Service{db: mockDB}
name, err := service.GetUser(1)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if name != "Alice" {
t.Errorf("got %s; want Alice", name)
}
}
```
---
### 7. 测试最佳实践
#### **1. 测试覆盖率**
```bash
# 查看覆盖率
go test -cover
# 生成覆盖率报告
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
```
---
#### **2. 测试隔离**
```go
// 每个测试独立
func Test1(t *testing.T) {
// setup
// test
// teardown
}
func Test2(t *testing.T) {
// 不依赖 Test1
}
```
---
#### **3. 使用 TestMain**
```go
func TestMain(m *testing.M) {
// 全局 setup
fmt.Println("setup before all tests")
m.Run()
// 全局 teardown
fmt.Println("teardown after all tests")
}
```
---
### 8. 阿里 P7 加分项
**深度理解**
- 理解 Go 错误处理的设计哲学(显式优于隐式)
- 理解 panic/recover 的实现机制
- 理解 table-driven test 的优势
**实战经验**
- 有编写高质量单元测试的经验(覆盖率 > 80%
- 有使用 Mock 进行测试的经验
- 有编写 Benchmark 进行性能优化的经验
**测试策略**
- 理解如何设计可测试的代码(依赖注入、接口)
- 理解如何进行集成测试和端到端测试
- 理解如何设计测试用例(边界条件、异常情况)