[teamai] Push 87 resource(s) from XingfenD
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
# Test-Driven Debugging
|
||||
|
||||
A failing test MUST be written before fixing a bug. Writing a failing test is often the fastest debugging path. It gives you a reproducible, isolated environment.
|
||||
|
||||
## Reproduce the Bug in a Test
|
||||
|
||||
```go
|
||||
func TestBugDescription(t *testing.T) {
|
||||
// Setup: exact conditions that trigger the bug
|
||||
svc := NewService(testConfig)
|
||||
|
||||
// Act: the operation that fails
|
||||
result, err := svc.Process(badInput)
|
||||
|
||||
// Assert: what should happen
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if result.Status != "ok" {
|
||||
t.Errorf("got status %q, want %q", result.Status, "ok")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Expand Edge Cases with Table Tests
|
||||
|
||||
When debugging, add edge cases to find the boundary of the bug:
|
||||
|
||||
```go
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want time.Duration
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid", "5s", 5 * time.Second, false},
|
||||
{"empty", "", 0, true},
|
||||
{"negative", "-1s", -time.Second, false},
|
||||
{"zero", "0s", 0, false},
|
||||
{"overflow", "99999999h", 0, true},
|
||||
{"whitespace", " 5s ", 0, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ParseDuration(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("got %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Useful Test Flags
|
||||
|
||||
```bash
|
||||
go test -v ./... # verbose output
|
||||
go test -run TestName -v ./pkg/... # single test
|
||||
go test -count=1 ./... # disable cache
|
||||
go test -timeout 10s ./... # short timeout (find hangs)
|
||||
go test -parallel 1 ./... # sequential execution
|
||||
go test -race ./... # race detector
|
||||
go test -cover ./... # coverage summary
|
||||
go test -coverprofile=c.out ./... && go tool cover -html=c.out # coverage report
|
||||
go test -failfast ./... # stop on first failure
|
||||
go test -shuffle=on ./... # randomize test order (Go 1.17+)
|
||||
```
|
||||
|
||||
## Debugging Flaky Tests
|
||||
|
||||
Flaky tests (pass sometimes, fail sometimes) are usually caused by one of:
|
||||
|
||||
1. **Shared mutable state between tests** — global variables, package-level maps, singletons
|
||||
- Fix: reset state in `TestMain` or use `t.Cleanup`
|
||||
2. **Test order dependence** — one test sets up state another test relies on
|
||||
- Diagnose: `go test -run TestSuspect -count=1` (run in isolation)
|
||||
- Diagnose: `go test -shuffle=on` (randomize order)
|
||||
- Fix: each test must set up its own preconditions
|
||||
3. **Timing sensitivity** — `time.Sleep` in tests, race between goroutines
|
||||
- Fix: use channels/waitgroups to synchronize, not sleeps
|
||||
4. **Port conflicts** — tests binding to fixed ports
|
||||
- Fix: use port `0` and read the assigned port
|
||||
5. **File system pollution** — tests writing to shared temp directories
|
||||
- Fix: use `t.TempDir()` for per-test directories
|
||||
|
||||
```bash
|
||||
# Confirm flakiness by running many times
|
||||
go test -count=100 -run TestSuspect ./pkg/... -failfast
|
||||
|
||||
# Check for parallelism issues
|
||||
go test -parallel 1 -count=10 ./pkg/...
|
||||
|
||||
# Check for order dependence
|
||||
go test -shuffle=on ./pkg/...
|
||||
```
|
||||
Reference in New Issue
Block a user