Skip to content

Weekly Review — Month 2 · Week 3 (Days 043–049)

Journal index · Roadmap › Month 2 Week 3

📅 The Week in One Line

Learned to prove and measure Go code with the standard testing package: table-driven t.Run subtests, parallelism + helpers, httptest for handlers, coverage profiling, testing.B benchmarks, and testing.F fuzzing with Example docs.

✅ What I Completed

  • Day 043 — Table-driven tests & subtests (reverse, wordfreq exercises)
  • Day 044 — t.Parallel, t.Helper, t.Cleanup, the loop-var capture trap
  • Day 045 — httptest recorder vs server (+ httptest-demo example, greeter exercise)
  • Day 046 — Coverage (-cover, go tool cover) & where testify fits
  • Day 047 — Benchmarks: b.N, b.ResetTimer, b.ReportAllocs (+ bench-demo example)
  • Day 048 — Fuzzing (testing.F) & Example functions (+ fuzz-roundtrip example)
  • Day 049 — Review & closed-book recall
  • Runnable examples: 3 (httptest-demo, bench-demo, fuzz-roundtrip)
  • Exercises solved: 3 (reverse, wordfreq, greeter) — table tests + fuzz + benchmark

💡 Lessons Learned

  • The table-driven + t.Run pattern is the backbone: named rows give per-case failures and go test -run TestX/case targeting.
  • t.Error collects all failures; t.Fatal stops the current (sub)test only — never call it from a spawned goroutine, it won't fail the test.
  • t.Parallel pauses a subtest until the parent's serial part returns, then runs siblings together; pair with tc := tc to be capture-safe on every Go version.
  • httptest.NewRecorder tests handlers in-process with no socket; reserve NewServer for real client/transport/TLS round trips.
  • Coverage is statement coverage — 100% is not correctness; chase error branches, not green lines. Use -covermode=atomic with -race.
  • A benchmark can lie two ways: timing setup (fix with b.ResetTimer) and dead-code elimination (sink the result). -benchmem/b.ReportAllocs often matters more than ns/op.
  • Fuzzing asserts invariants (round-trip, idempotence, never-panic, stays-valid) over generated inputs; plain go test runs only seeds, -fuzz mutates and saves failing inputs to testdata.
  • Example functions with // Output: are tests and rendered docs on pkg.go.dev.

💪 Strengths (what clicked)

  • Writing table-driven subtests fast and reading got-vs-want failures without an assertion lib.
  • httptest.NewRecorder mechanics — calling ServeHTTP directly felt natural.
  • Spotting the UTF-8 bug a byte-reverse hides, and expressing it as a fuzz invariant.

🧩 Weaknesses (what's still fuzzy)

  • Interpreting noisy benchmark numbers and using benchstat confidently (need ≥10 -count runs).
  • Choosing -coverpkg boundaries for cross-package coverage credit.
  • Minimization/shrinking internals of the fuzz engine.

🔁 Spaced-Repetition Re-quiz (topics from earlier weeks)

  1. Q: (Month 1) Nil-interface trap: when is an interface holding a nil pointer != nil?
    AAn interface value is nil only when both its type and value are nil. A non-nil concrete type with a nil pointer value makes the interface non-nil — the classic return err where err is a typed-nil *MyError.
  2. Q: (Month 2 W1) Why must you Flush a bufio.Writer?
    AIt buffers writes in memory; without Flush the pending bytes never reach the underlying writer — silent data loss.
  3. Q: (Month 2 W1) string(65) — what do you get and what should you use?
    A"A" (rune→string conversion), not "65". Use strconv.Itoa/FormatInt for number→text.
  4. Q: (This week) Who sets b.N in a benchmark?
    AThe framework auto-tunes it upward until the loop runs ~1s, then reports total/b.N as ns/op.
  5. Q: (This week) What does plain go test do with FuzzXxx?
    ARuns it against the seed corpus only (deterministic); -fuzz=FuzzXxx enters the mutation engine.

🎯 Action Items

  • Run go test -bench=. -benchmem -count=10 ./exercises/month-02/week-3/reverse and compare with benchstat.
  • Add an ExampleReverse and an ExampleReverse_unicode to the reverse package.
  • Fuzz reverse for 30s (-fuzz=FuzzReverse -fuzztime=30s) and commit any testdata seed it finds.
  • Generate an HTML coverage report for week-3 and look for uncovered error branches.

🚀 Next Week Goals

  • Profiling with pprof (CPU/heap) to explain why a benchmark differs.
  • Static analysis: go vet, staticcheck, and go test -race in CI.
  • Modules & versioning: go.mod, semantic import versioning, go mod tidy.
  • Build & release tooling: go build flags, build tags, cross-compilation.

📊 Metrics

Hours Days hit Exercises Commits Avg confidence
10.5 7/7 3 7 3.⅗

Suggested commit: docs(journal): month 2 week 3 review