Initial commit
This commit is contained in:
14
.claude-plugin/plugin.json
Normal file
14
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "nk-go-development",
|
||||||
|
"description": "Go-specific TDD patterns, test runners, table-driven tests, and testify usage",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Cole Kennedy"
|
||||||
|
},
|
||||||
|
"skills": [
|
||||||
|
"./skills"
|
||||||
|
],
|
||||||
|
"commands": [
|
||||||
|
"./commands"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# nk-go-development
|
||||||
|
|
||||||
|
Go-specific TDD patterns, test runners, table-driven tests, and testify usage
|
||||||
21
commands/go-test-single.md
Normal file
21
commands/go-test-single.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
description: Run a single Go test by name with verbose output
|
||||||
|
---
|
||||||
|
|
||||||
|
# Run Single Go Test
|
||||||
|
|
||||||
|
Run a specific Go test function. Provide the test name and optionally the package path.
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```bash
|
||||||
|
# Test in current directory
|
||||||
|
go test -v -run $ARGUMENTS
|
||||||
|
|
||||||
|
# Test in specific package
|
||||||
|
go test -v ./path/to/package -run $ARGUMENTS
|
||||||
|
|
||||||
|
# With failfast
|
||||||
|
go test -v --failfast -run $ARGUMENTS
|
||||||
|
```
|
||||||
|
|
||||||
|
Ask for the test name if not provided in the request, then execute the test with verbose output and show the results.
|
||||||
49
plugin.lock.json
Normal file
49
plugin.lock.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:colek42/claude-plugins:nk-go-development",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "b8107922d5896882079b6293b06a450a99a55722",
|
||||||
|
"treeHash": "f91009b2d87fea9491706cae6817b374e5e7bee59490f1c820408b02fc81025a",
|
||||||
|
"generatedAt": "2025-11-28T10:15:45.397207Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "nk-go-development",
|
||||||
|
"description": "Go-specific TDD patterns, test runners, table-driven tests, and testify usage",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "8446c4d684110815129531a7f7352da776cadaa3214f26b509ead70213254ba8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "910f3c038965effa37756af9a0f8808e1855abcb150c3ca9f0903db647d05e21"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/go-test-single.md",
|
||||||
|
"sha256": "1fa071631506d0e104cd8c9d4a6e76d7367851e00534e90d76afdddb9e772bee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/go-tdd-patterns/SKILL.md",
|
||||||
|
"sha256": "23a6b2bd3817a221641bcddb1620c7a091ce89dc2346e4005b822851c54a8b50"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "f91009b2d87fea9491706cae6817b374e5e7bee59490f1c820408b02fc81025a"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
198
skills/go-tdd-patterns/SKILL.md
Normal file
198
skills/go-tdd-patterns/SKILL.md
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
# Go TDD Patterns & Best Practices
|
||||||
|
|
||||||
|
This skill provides Go-specific testing patterns and conventions.
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
Activates when:
|
||||||
|
- Writing Go code
|
||||||
|
- Creating or modifying Go tests
|
||||||
|
- Reviewing Go test coverage
|
||||||
|
- Refactoring Go code
|
||||||
|
|
||||||
|
## Test Organization
|
||||||
|
|
||||||
|
### File Naming
|
||||||
|
- Unit tests: `*_test.go`
|
||||||
|
- Integration tests: `e2e_test.go` or `integration_test.go`
|
||||||
|
- Place tests alongside the code they test
|
||||||
|
|
||||||
|
### Test Function Naming
|
||||||
|
```go
|
||||||
|
func TestFunctionName(t *testing.T) // Basic test
|
||||||
|
func TestFunctionName_Scenario(t *testing.T) // Specific scenario
|
||||||
|
func TestFunctionName_EdgeCase(t *testing.T) // Edge case
|
||||||
|
```
|
||||||
|
|
||||||
|
## Table-Driven Tests
|
||||||
|
|
||||||
|
Use table-driven tests for multiple inputs/scenarios:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TestValidation(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
want bool
|
||||||
|
wantErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid input",
|
||||||
|
input: "test",
|
||||||
|
want: true,
|
||||||
|
wantErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty input",
|
||||||
|
input: "",
|
||||||
|
want: false,
|
||||||
|
wantErr: ErrEmptyInput,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := Validate(tt.input)
|
||||||
|
|
||||||
|
if tt.wantErr != nil {
|
||||||
|
require.ErrorIs(t, err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testify Assertions
|
||||||
|
|
||||||
|
### require vs assert
|
||||||
|
|
||||||
|
**Use `testify/require`** - Stop test execution on failure:
|
||||||
|
```go
|
||||||
|
require.NoError(t, err) // Stop if error
|
||||||
|
require.NotNil(t, result) // Stop if nil
|
||||||
|
require.Equal(t, expected, actual) // Stop if not equal
|
||||||
|
require.ErrorIs(t, err, ErrExpected) // Stop if wrong error
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use `testify/assert`** - Continue test execution:
|
||||||
|
```go
|
||||||
|
assert.Equal(t, expected, actual) // Continue on failure
|
||||||
|
assert.True(t, condition) // Continue on failure
|
||||||
|
assert.Contains(t, slice, element) // Continue on failure
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pattern:** Use `require` for prerequisites, `assert` for multiple checks
|
||||||
|
|
||||||
|
## Mock External Dependencies
|
||||||
|
|
||||||
|
Mock external dependencies for unit tests:
|
||||||
|
- Network calls
|
||||||
|
- Filesystem operations
|
||||||
|
- Time-dependent code
|
||||||
|
- External services
|
||||||
|
|
||||||
|
```go
|
||||||
|
type mockClient struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockClient) FetchData(ctx context.Context) ([]byte, error) {
|
||||||
|
args := m.Called(ctx)
|
||||||
|
return args.Get(0).([]byte), args.Error(1)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Error Cases
|
||||||
|
|
||||||
|
Always test error cases and edge conditions:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TestHandler_Errors(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
setup func(*mockDeps)
|
||||||
|
wantErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "database connection failed",
|
||||||
|
setup: func(m *mockDeps) {
|
||||||
|
m.db.On("Connect").Return(ErrConnFailed)
|
||||||
|
},
|
||||||
|
wantErr: ErrConnFailed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid input",
|
||||||
|
setup: func(m *mockDeps) {
|
||||||
|
// No setup needed
|
||||||
|
},
|
||||||
|
wantErr: ErrInvalidInput,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
m := newMockDeps()
|
||||||
|
if tt.setup != nil {
|
||||||
|
tt.setup(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := Handler(m)
|
||||||
|
require.ErrorIs(t, err, tt.wantErr)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration Test Patterns
|
||||||
|
|
||||||
|
Use build tags for integration tests:
|
||||||
|
|
||||||
|
```go
|
||||||
|
//go:build integration
|
||||||
|
// +build integration
|
||||||
|
|
||||||
|
package mypackage_test
|
||||||
|
|
||||||
|
func TestIntegration_RealDatabase(t *testing.T) {
|
||||||
|
// Integration test code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Run with: `go test -tags=integration ./...`
|
||||||
|
|
||||||
|
## Test Coverage Standards
|
||||||
|
|
||||||
|
- Minimum coverage: 90% lines and branches
|
||||||
|
- Every exported function must have tests
|
||||||
|
- Critical paths need both positive and negative tests
|
||||||
|
- Edge cases must be explicitly tested
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run all tests
|
||||||
|
go test -v ./...
|
||||||
|
|
||||||
|
# Run with race detector
|
||||||
|
go test -v -race ./...
|
||||||
|
|
||||||
|
# Run with coverage
|
||||||
|
go test -v -cover ./...
|
||||||
|
|
||||||
|
# Run single test
|
||||||
|
go test -v ./path/to/package -run TestName
|
||||||
|
|
||||||
|
# Run with failfast
|
||||||
|
go test -v --failfast ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Documentation
|
||||||
|
|
||||||
|
Tests serve as documentation:
|
||||||
|
- Use descriptive test names
|
||||||
|
- Use table-driven test `name` field to describe scenario
|
||||||
|
- Add comments only for complex setup or non-obvious behavior
|
||||||
Reference in New Issue
Block a user