import "github.com/stretchr/testify/assert"
func TestAdd(t *testing.T) {
assert.Equal(t, 4, 2+2)
assert.NotEqual(t, 5, 2+2)
assert.True(t, true)
assert.Nil(t, nil)
assert.NotNil(t, &struct{}{})
assert.Contains(t, "hello world", "world")
}
func TestWithMessages(t *testing.T) {
assert.Equal(t, 200, resp.StatusCode, "status should be 200")
}
import "github.com/stretchr/testify/require"
func TestDB(t *testing.T) {
db, err := sql.Open("postgres", dsn)
require.NoError(t, err, "database connection must succeed")
defer db.Close()
require.NotNil(t, db)
var count int
err = db.QueryRow("SELECT COUNT(*) FROM users").Scan(&count)
require.NoError(t, err)
}
func TestEquality(t *testing.T) {
assert.Equal(t, "hello", "hello")
assert.NotEqual(t, "hello", "world")
assert.EqualValues(t, uint32(42), int32(42))
assert.EqualExportedValues(t, User{Name: "Alice"}, gotUser)
type Point struct{ X, Y int }
assert.Equal(t, Point{1, 2}, Point{1, 2})
}
func TestNilChecks(t *testing.T) {
var ptr *int
assert.Nil(t, ptr)
assert.Nil(t, error(nil))
s := []int{}
assert.NotNil(t, s)
assert.NotNil(t, &struct{}{})
var ch chan int
assert.Nil(t, ch)
var m map[string]int
assert.Nil(t, m)
}
func TestBool(t *testing.T) {
assert.True(t, 1 == 1)
assert.True(t, strings.Contains("hello", "ell"))
assert.True(t, len([]int{1, 2, 3}) == 3)
assert.False(t, 1 == 2)
assert.False(t, errors.Is(err, os.ErrNotExist))
}
func TestContains(t *testing.T) {
assert.Contains(t, "hello world", "world")
assert.Contains(t, []string{"a", "b", "c"}, "b")
assert.Contains(t, map[string]int{"a": 1, "b": 2}, "a")
assert.NotContains(t, "hello", "xyz")
assert.NotContains(t, []int{1, 2, 3}, 5)
assert.ElementsMatch(t, []int{3, 1, 2}, []int{1, 2, 3})
assert.Subset(t, []int{1, 2, 3, 4}, []int{2, 3})
}
func TestJSON(t *testing.T) {
assert.JSONEq(t,
`{"name":"Alice","age":30}`,
`{"age":30,"name":"Alice"}`,
)
assert.YAMLEq(t,
"name: Alice\nage: 30\n",
"age: 30\nname: Alice\n",
)
}
func TestStructCompare(t *testing.T) {
expected := User{Name: "Alice", Age: 30}
assert.Equal(t, expected, gotUser)
}
type MockRepo struct {
mock.Mock
}
func (m *MockRepo) GetByID(id int) (*User, error) {
args := m.Called(id)
return args.Get(0).(*User), args.Error(1)
}
func TestGetUser(t *testing.T) {
repo := new(MockRepo)
repo.On("GetByID", 42).Return(&User{Name: "Alice"}, nil)
svc := NewUserService(repo)
user, err := svc.Get(42)
assert.NoError(t, err)
assert.Equal(t, "Alice", user.Name)
repo.AssertExpectations(t)
repo.AssertCalled(t, "GetByID", 42)
repo.AssertNumberOfCalls(t, "GetByID", 1)
}
type UserSuite struct {
suite.Suite
db *sql.DB
svc *UserService
}
func (s *UserSuite) SetupSuite() {
s.db, _ = sql.Open("sqlite3", ":memory:")
s.svc = NewUserService(s.db)
}
func (s *UserSuite) TearDownSuite() {
s.db.Close()
}
func (s *UserSuite) TestCreate() {
user, err := s.svc.Create("Alice")
s.NoError(err)
s.Equal("Alice", user.Name)
}
func TestUserSuite(t *testing.T) {
suite.Run(t, new(UserSuite))
}
type DBSuite struct {
suite.Suite
db *sql.DB
tx *sql.Tx
}
func (s *DBSuite) SetupSuite() {
s.db, _ = sql.Open("postgres", dsn)
}
func (s *DBSuite) TearDownSuite() {
s.db.Close()
}
func (s *DBSuite) BeforeTest(suiteName, testName string) {
s.tx, _ = s.db.Begin()
}
func (s *DBSuite) AfterTest(suiteName, testName string) {
s.tx.Rollback()
}
func (s *DBSuite) TestInsert() {
_, err := s.tx.Exec("INSERT INTO users (name) VALUES ($1)", "Alice")
s.NoError(err)
}
import "github.com/stretchr/testify/assert/http"
func TestHandler(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
fmt.Fprint(w, `{"status":"ok"}`)
})
assert.HTTPSuccess(t, handler, "GET", "/health", nil)
assert.HTTPStatusCode(t, handler, "GET", "/health", nil, 200)
assert.HTTPBodyContains(t, handler, "GET", "/health", nil, "ok")
assert.HTTPBodyNotContains(t, handler, "GET", "/health", nil, "error")
}
func TestAsync(t *testing.T) {
state := &atomic.Int32{}
go func() {
time.Sleep(100 * time.Millisecond)
state.Store(42)
}()
assert.Eventually(t, func() bool {
return state.Load() == 42
}, 2*time.Second, 50*time.Millisecond)
assert.Never(t, func() bool {
return state.Load() == 99
}, 1*time.Second, 50*time.Millisecond)
}
func TestEventuallyWithT(t *testing.T) {
assert.EventuallyWithT(t, func(c *assert.CollectT) {
resp, _ := http.Get("http://localhost:8080/health")
assert.Equal(c, 200, resp.StatusCode)
}, 5*time.Second, 100*time.Millisecond)
}
func TestErrors(t *testing.T) {
_, err := strconv.Atoi("notanumber")
assert.Error(t, err)
assert.ErrorIs(t, err, strconv.ErrSyntax)
wrapped := fmt.Errorf("parse: %w", err)
assert.ErrorIs(t, wrapped, strconv.ErrSyntax)
assert.EqualError(t, err, `strconv.Atoi: parsing "notanumber": invalid syntax`)
assert.ErrorContains(t, err, "invalid syntax")
_, noErr := strconv.Atoi("42")
assert.NoError(t, noErr)
}
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive", 2, 3, 5},
{"negative", -1, -1, -2},
{"zero", 0, 0, 0},
{"mixed", -5, 10, 5},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, Add(tt.a, tt.b))
})
}
}
func TestWithSuite(t *testing.T) {
tests := []struct {
input string
expected bool
}{
{"valid@email.com", true},
{"invalid", false},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
assert.Equal(t, tt.expected, IsValidEmail(tt.input))
})
}
}
import "github.com/stretchr/testify/assert"
func TestAdd(t *testing.T) {
assert.Equal(t, 4, 2+2)
assert.NotEqual(t, 5, 2+2)
assert.True(t, true)
assert.Nil(t, nil)
assert.NotNil(t, &struct{}{})
assert.Contains(t, "hello world", "world")
}
func TestWithMessages(t *testing.T) {
assert.Equal(t, 200, resp.StatusCode, "状态码应为 200")
}
import "github.com/stretchr/testify/require"
func TestDB(t *testing.T) {
db, err := sql.Open("postgres", dsn)
require.NoError(t, err, "数据库连接必须成功")
defer db.Close()
require.NotNil(t, db)
var count int
err = db.QueryRow("SELECT COUNT(*) FROM users").Scan(&count)
require.NoError(t, err)
}
func TestEquality(t *testing.T) {
assert.Equal(t, "hello", "hello")
assert.NotEqual(t, "hello", "world")
assert.EqualValues(t, uint32(42), int32(42))
assert.EqualExportedValues(t, User{Name: "Alice"}, gotUser)
type Point struct{ X, Y int }
assert.Equal(t, Point{1, 2}, Point{1, 2})
}
func TestNilChecks(t *testing.T) {
var ptr *int
assert.Nil(t, ptr)
assert.Nil(t, error(nil))
s := []int{}
assert.NotNil(t, s)
assert.NotNil(t, &struct{}{})
var ch chan int
assert.Nil(t, ch)
var m map[string]int
assert.Nil(t, m)
}
func TestBool(t *testing.T) {
assert.True(t, 1 == 1)
assert.True(t, strings.Contains("hello", "ell"))
assert.True(t, len([]int{1, 2, 3}) == 3)
assert.False(t, 1 == 2)
assert.False(t, errors.Is(err, os.ErrNotExist))
}
func TestContains(t *testing.T) {
assert.Contains(t, "hello world", "world")
assert.Contains(t, []string{"a", "b", "c"}, "b")
assert.Contains(t, map[string]int{"a": 1, "b": 2}, "a")
assert.NotContains(t, "hello", "xyz")
assert.NotContains(t, []int{1, 2, 3}, 5)
assert.ElementsMatch(t, []int{3, 1, 2}, []int{1, 2, 3})
assert.Subset(t, []int{1, 2, 3, 4}, []int{2, 3})
}
func TestJSON(t *testing.T) {
assert.JSONEq(t,
`{"name":"Alice","age":30}`,
`{"age":30,"name":"Alice"}`,
)
assert.YAMLEq(t,
"name: Alice\nage: 30\n",
"age: 30\nname: Alice\n",
)
}
func TestStructCompare(t *testing.T) {
expected := User{Name: "Alice", Age: 30}
assert.Equal(t, expected, gotUser)
}
type MockRepo struct {
mock.Mock
}
func (m *MockRepo) GetByID(id int) (*User, error) {
args := m.Called(id)
return args.Get(0).(*User), args.Error(1)
}
func TestGetUser(t *testing.T) {
repo := new(MockRepo)
repo.On("GetByID", 42).Return(&User{Name: "Alice"}, nil)
svc := NewUserService(repo)
user, err := svc.Get(42)
assert.NoError(t, err)
assert.Equal(t, "Alice", user.Name)
repo.AssertExpectations(t)
repo.AssertCalled(t, "GetByID", 42)
repo.AssertNumberOfCalls(t, "GetByID", 1)
}
type UserSuite struct {
suite.Suite
db *sql.DB
svc *UserService
}
func (s *UserSuite) SetupSuite() {
s.db, _ = sql.Open("sqlite3", ":memory:")
s.svc = NewUserService(s.db)
}
func (s *UserSuite) TearDownSuite() {
s.db.Close()
}
func (s *UserSuite) TestCreate() {
user, err := s.svc.Create("Alice")
s.NoError(err)
s.Equal("Alice", user.Name)
}
func TestUserSuite(t *testing.T) {
suite.Run(t, new(UserSuite))
}
type DBSuite struct {
suite.Suite
db *sql.DB
tx *sql.Tx
}
func (s *DBSuite) SetupSuite() {
s.db, _ = sql.Open("postgres", dsn)
}
func (s *DBSuite) TearDownSuite() {
s.db.Close()
}
func (s *DBSuite) BeforeTest(suiteName, testName string) {
s.tx, _ = s.db.Begin()
}
func (s *DBSuite) AfterTest(suiteName, testName string) {
s.tx.Rollback()
}
func (s *DBSuite) TestInsert() {
_, err := s.tx.Exec("INSERT INTO users (name) VALUES ($1)", "Alice")
s.NoError(err)
}
import "github.com/stretchr/testify/assert/http"
func TestHandler(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
fmt.Fprint(w, `{"status":"ok"}`)
})
assert.HTTPSuccess(t, handler, "GET", "/health", nil)
assert.HTTPStatusCode(t, handler, "GET", "/health", nil, 200)
assert.HTTPBodyContains(t, handler, "GET", "/health", nil, "ok")
assert.HTTPBodyNotContains(t, handler, "GET", "/health", nil, "error")
}
func TestAsync(t *testing.T) {
state := &atomic.Int32{}
go func() {
time.Sleep(100 * time.Millisecond)
state.Store(42)
}()
assert.Eventually(t, func() bool {
return state.Load() == 42
}, 2*time.Second, 50*time.Millisecond)
assert.Never(t, func() bool {
return state.Load() == 99
}, 1*time.Second, 50*time.Millisecond)
}
func TestEventuallyWithT(t *testing.T) {
assert.EventuallyWithT(t, func(c *assert.CollectT) {
resp, _ := http.Get("http://localhost:8080/health")
assert.Equal(c, 200, resp.StatusCode)
}, 5*time.Second, 100*time.Millisecond)
}
func TestErrors(t *testing.T) {
_, err := strconv.Atoi("notanumber")
assert.Error(t, err)
assert.ErrorIs(t, err, strconv.ErrSyntax)
wrapped := fmt.Errorf("parse: %w", err)
assert.ErrorIs(t, wrapped, strconv.ErrSyntax)
assert.EqualError(t, err, `strconv.Atoi: parsing "notanumber": invalid syntax`)
assert.ErrorContains(t, err, "invalid syntax")
_, noErr := strconv.Atoi("42")
assert.NoError(t, noErr)
}
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"正数", 2, 3, 5},
{"负数", -1, -1, -2},
{"零值", 0, 0, 0},
{"混合", -5, 10, 5},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, Add(tt.a, tt.b))
})
}
}
func TestWithSuite(t *testing.T) {
tests := []struct {
input string
expected bool
}{
{"valid@email.com", true},
{"invalid", false},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
assert.Equal(t, tt.expected, IsValidEmail(tt.input))
})
}
}