golang-testing
テスト駆動開発とGoコードの高品質を保証するための包括的なテスト戦略。
DeepseekModel
Curated skill
Quality Excellent · 90
v1.0.0
Get
https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-ja-jp-skills-golang-testing-skill-md&format=skill
Download .skill
Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name golang-testing description テスト駆動開発とGoコードの高品質を保証するための包括的なテスト戦略。 Go テスト テスト駆動開発(TDD)とGoコードの高品質を保証するための包括的なテスト戦略。 いつ有効化するか 新しいGoコードを書くとき Goコードをレビューするとき 既存のテストを改善するとき テストカバレッジを向上させるとき デバッグとバグ修正時 核となる原則 1. テスト駆動開発(TDD)ワークフロー 失敗するテストを書き、実装し、リファクタリングするサイクルに従います。 // 1. テストを書く(失敗) func TestCalculateTotal (t *testing.T) { total := CalculateTotal([] float64 { 10.0 , 20.0 , 30.0 }) want := 60.0 if total != want { t.Errorf( "got %f, want %f" , total, want) } } // 2. 実装する(テストを通す) func CalculateTotal (prices [] float64 ) float64 { var total float64 for _, price := range prices { total += price } return total } // 3. リファクタリング // テストを壊さずにコードを改善 2. テーブル駆動テスト 複数のケースを体系的にテストします。 func TestAdd (t *testing.T) { tests := [] struct { name string a, b int want int }{ { "positive numbers" , 2 , 3 , 5 }, { "negative numbers" , -2 , -3 , -5 }, { "mixed signs" , -2 , 3 , 1 }, { "zeros" , 0 , 0 , 0 }, } for _, tt := range tests { t.Run(tt.name, func (t *testing.T) { got := Add(tt.a, tt.b) if got != tt.want { t.Errorf( "Add(%d, %d) = %d; want %d" , tt.a, tt.b, got, tt.want) } }) } } 3. サブテスト サブテストを使用した論理的なテストの構成。 func TestUser (t *testing.T) { t.Run( "validation" , func (t *testing.T) { t.Run( "empty email" , func (t *testing.T) { user := User{Email: "" } if err := user.Validate(); err == nil { t.Error( "expected validation error" ) } }) t.Run( "valid email" , func (t *testing.T) { user := User{Email: "test@example.com" } if err := user.Validate(); err != nil { t.Errorf( "unexpected error: %v" , err) } }) }) t.Run( "serialization" , func (t *testing.T) { // 別のテストグループ }) } テスト構成 ファイル構成 mypackage/ ├── user.go ├── user_test.go # ユニットテスト ├── integration_test.go # 統合テスト ├── testdata/ # テストフィクスチャ │ ├── valid_user.json │ └── invalid_user.json └── export_test.go # 内部テスト用の非公開エクスポート テストパッケージ // user_test.go - 同じパッケージ(ホワイトボックステスト) package user func TestInternalFunction (t *testing.T) { // 内部をテストできる } // user_external_test.go - 外部パッケージ(ブラックボックステスト) package user_test import "myapp/user" func TestPublicAPI (t *testing.T) { // 公開APIのみをテスト } アサーションとヘルパー 基本的なアサーション func TestBasicAssertions (t *testing.T) { // 等価性 got := Calculate() want := 42 if got != want { t.Errorf( "got %d, want %d" , got, want) } // エラーチェック _, err := Process() if err != nil { t.Fatalf( "unexpected error: %v" , err) } // nil チェック result := GetResult() if result == nil { t.Fatal( "expected non-nil result" ) } } カスタムヘルパー関数 // ヘルパーとしてマーク(スタックトレースに表示されない) func assertEqual (t *testing.T, got, want interface {}) { t.Helper() if got != want { t.Errorf( "got %v, want %v" , got, want) } } func assertNoError (t *testing.T, err error ) { t.Helper() if err != nil { t.Fatalf( "unexpected error: %v" , err) } } // 使用例 func TestWithHelpers (t *testing.T) { result, err := Process() assertNoError(t, err) assertEqual(t, result.Status, "success" ) } ディープ等価性チェック import "reflect" func assertDeepEqual (t *testing.T, got, want interface {}) { t.Helper() if !reflect.DeepEqual(got, want) { t.Errorf( "got %+v, want %+v" , got, want) } } func TestStructEquality (t *testing.T) { got := User{Name: "Alice" , Age: 30 } want := User{Name: "Alice" , Age: 30 } assertDeepEqual(t, got, want) } モッキングとスタブ インターフェースベースのモック // 本番コード type UserStore interface { GetUser(id string ) (*User, error ) SaveUser(user *User) error } type UserService struct { store UserStore } // テストコード type MockUserStore struct { users map [ string ]*User err error } func (m *MockUserStore) GetUser(id string ) (*User, error ) { if m.err != nil { return nil , m.err } return m.users[id], nil } func (m *MockUserStore) SaveUser(user *User) error { if m.err != nil { return m.err } m.users[user.ID] = user return nil } // テスト func TestUserService (t *testing.T) { mock := &MockUserStore{ users: make ( map [ string ]*User), } service := &UserService{store: mock} // サービスをテスト... } 時間のモック // プロダクションコード - 時間を注入可能にする type TimeProvider interface { Now() time.Time } type RealTime struct {} func (RealTime) Now() time.Time { return time.Now() } type Service struct { time TimeProvider } // テストコード type MockTime struct { current time.Time } func (m MockTime) Now() time.Time { return m.current } func TestTimeDependent (t *testing.T) { mockTime := MockTime{ current: time.Date( 2024 , 1 , 1 , 0 , 0 , 0 , 0 , time.UTC), } service := &Service{time: mockTime} // 固定時間でテスト... } HTTP クライアントのモック type HTTPClient interface { Do(req *http.Request) (*http.Response, error ) } type MockHTTPClient struct { response *http.Response err error } func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error ) { return m.response, m.err } func TestAPICall (t *testing.T) { mockClient := &MockHTTPClient{ response: &http.Response{ StatusCode: 200 , Body: io.NopCloser(strings.NewReader( `{"status":"ok"}` )), }, } api := &APIClient{client: mockClient} // APIクライアントをテスト... } HTTPハンドラーのテスト httptest の使用 func TestHandler (t *testing.T) { handler := http.HandlerFunc(MyHandler) req := httptest.NewRequest( "GET" , "/users/123" , nil ) rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) // ステータスコードをチェック if rec.Code != http.StatusOK { t.Errorf( "got status %d, want %d" , rec.Code, http.StatusOK) } // レスポンスボディをチェック var response map [ string ] interface {} if err := json.NewDecoder(rec.Body).Decode(&response); err != nil { t.Fatalf( "failed to decode response: %v" , err) } if response[ "id" ] != "123" { t.Errorf( "got id %v, want 123" , response[ "id" ]) } } ミドルウェアのテスト func TestAuthMiddleware (t *testing.T) { // ダミーハンドラー nextHandler := http.HandlerFunc( func (w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) // ミドルウェアでラップ handler := AuthMiddleware(nextHandler) tests := [] struct { name string token string wantStatus int }{ { "valid token" , "valid-token" , http.StatusOK}, { "invalid token" , "invalid" , http.StatusUnauthorized}, { "no token" , "" , http.StatusUnauthorized}, } for _, tt := range tests { t.Run(tt.name, func (t *testing.T) { req := httptest.NewRequest( "GET" , "/" , nil ) if tt.token != "" { req.Header.Set( "Authorization" , "Bearer " +tt.token) } rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != tt.wantStatus { t.Errorf( "got status %d, want %d" , rec.Code, tt.wantStatus) } }) } } テストサーバー func TestAPIIntegration (t *testing.T) { // テストサーバーを作成 server := httptest.NewServer(http.HandlerFunc( func (w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode( map [ string ] string { "message" : "hello" , }) })) defer server.Close() // 実際のHTTPリクエストを行う resp, err := http.Get(server.URL) if err != nil { t.Fatalf( "request failed: %v" , err) } defer resp.Body.Close() // レスポンスを検証 var result map [ string ] string json.NewDecoder(resp.Body).Decode(&result) if result[ "message" ] != "hello" { t.Errorf( "got %s, want hello" , result[ "message" ]) } } データベーステスト トランザクションを使用したテストの分離 func TestUserRepository (t *testing.T) { db := setupTestDB(t) defer db.Close() tests := [] struct { name string fn func (*testing.T, *sql.DB) }{ { "create user" , testCreateUser}, { "find user" , testFindUser}, { "update user" , testUpdateUser}, } for _, tt := range tests { t.Run(tt.name, func (t *testing.T) { tx, err := db.Begin() if err != nil { t.Fatal(err) } defer tx.Rollback() // テスト後にロールバック tt.fn(t, tx) }) } } テストフィクスチャ func setupTestDB (t *testing.T) *sql.DB { t.Helper() db, err := sql.Open( "postgres" , "postgres://localhost/test" ) if err != nil { t.Fatalf( "failed to connect: %v" , err) } // スキーマを移行 if err := runMigrations(db); err != nil { t.Fatalf( "migrations failed: %v" , err) } return db } func seedTestData (t *testing.T, db *sql.DB) { t.Helper() fixtures := [] string { `INSERT INTO users (id, email) VALUES ('1', 'test@example.com')` , `INSERT INTO posts (id, user_id, title) VALUES ('1', '1', 'Test Post')` , } for _, query := range fixtures { if _, err := db.Exec(query); err != nil { t.Fatalf( "failed to seed data: %v" , err) } } } ベンチマーク 基本的なベンチマーク func BenchmarkCalculation (b *testing.B) {
Keywords that activate this skill. Click one to copy it.
This skill does not provide trigger words.
The downloaded .skill package contains the following fields.
| Field | Description |
|---|---|
| format | Format tag (skill/v1) |
| skill_id | Unique skill ID |
| name | Skill name |
| version | Version |
| description | Description |
| category | Categories (array) |
| trigger_words | Trigger words |
| tags | Tags |
| source | Source |
| source_url | Source URL (this page) |
| exported_at | Exported at (set per download) |
| system_prompt | System prompt body |
| model_config | Model config: provider / model / temperature / max_tokens / top_p |
| examples | Examples |
| install_guide | Import guide for Coze / Dify / Claude / custom frameworks |
The same skill can be exported in different platform formats.