Part 8 is complete. The BlogApp now has a comprehensive, automated test suite across all layers: unit tests that verify business rules in isolation, integration tests that verify the HTTP pipeline and database interactions, Angular unit tests that verify component and service behaviour, and E2E tests that verify critical user journeys. The CI pipeline runs all tiers automatically on every PR, with coverage thresholds preventing regression. This is the foundation of confident, sustainable software development.
Part 8 Testing Summary
// ── BlogApp Test Portfolio Summary ────────────────────────────────────────
// ── UNIT TESTS (~300 tests, ~30 seconds) ──────────────────────────────────
// Tool: xUnit + FluentAssertions + Moq + Bogus
//
// PostsService:
// - CreateAsync: slug uniqueness, auth check, default values [5 tests]
// - PublishAsync: status check, ownership, success path [4 tests]
// - GetPublishedAsync: pagination, ordering, category filter [6 tests]
// - SoftDeleteAsync: fields set, cascade [3 tests]
//
// AuthService / JwtTokenService:
// - GenerateToken: claims, expiry, signing [5 tests]
// - Login: success, wrong password, lockout [4 tests]
// - RefreshToken: valid cookie, expired, revoked [4 tests]
//
// SlugGenerator: [Theory] with 20+ input/output pairs [1 test / 20 cases]
// FileUploadValidator: [Theory] with boundary values [1 test / 6 cases]
// Pagination: [Theory] with boundary values [1 test / 7 cases]
//
// AuditInterceptor:
// - Sets CreatedAt/CreatedBy on Add [2 tests]
// - Sets only UpdatedAt/UpdatedBy on Modify [2 tests]
// ── INTEGRATION TESTS (~80 tests, ~3 minutes) ─────────────────────────────
// Tool: WebApplicationFactory + Respawn + SQLite/LocalDB
//
// Posts endpoints:
// - GET /api/posts: 200 with paged result [1 test]
// - GET /api/posts/{slug}: 200, 404 [2 tests]
// - POST /api/posts: 201, 401, 422, 409 [4 tests]
// - PUT /api/posts/{id}: 200, 403, 412 [3 tests]
// - DELETE /api/posts/{id}: 204, 403, soft delete verified [3 tests]
//
// Auth endpoints:
// - POST /api/auth/login: 200+cookie, 401 [2 tests]
// - POST /api/auth/refresh: 200, 401 [2 tests]
// - Authorization: 401 no token, 403 wrong role, 200 correct [3 tests]
// ── ANGULAR UNIT TESTS (~100 tests, ~20 seconds) ──────────────────────────
// Tool: Jest + TestBed + HttpClientTestingModule
//
// PostsApiService: GET with params, 404 handling, POST auth [5 tests]
// AuthService: login updates signals, logout clears [4 tests]
// CdnUrlPipe: null, blob URL, non-blob URL [3 tests]
// slugFormatValidator: valid/invalid inputs [20 cases]
// PostListComponent: renders posts, empty state, error state [4 tests]
// PostFormComponent: validation, submit, unsaved changes guard [5 tests]
// ── E2E TESTS (~20 tests, ~5 minutes parallel) ────────────────────────────
// Tool: Cypress + cy.session() + cy.intercept()
//
// Public browsing: list loads, navigate to post, filter [3 tests]
// Admin creation: create, publish, verify in public list [1 test]
// Comment flow: submit, verify in real-time [1 test]
// Auth flow: login, logout, protected route redirect [3 tests]
// Error states: API down, 404 page, 403 page [3 tests]
// ── CI PIPELINE ───────────────────────────────────────────────────────────
// Total time: ~10 minutes (parallel where possible)
// Coverage: 82% line, 74% branch (above thresholds)
// Mutation score: 71% on service layer (from weekly Stryker run)
result.Should().NotBeNull() when it should assert on specific fields), improve it. Small, continuous improvements to the test suite compound over time into a genuinely valuable safety net — the opposite of the “test debt” spiral where tests are always planned for later.🎓 Part 8 Complete — Testing Summary
| Chapter | Topic | Key Tools |
|---|---|---|
| 77 | Testing strategy, pyramid, TDD | xUnit, Jasmine, Cypress |
| 78 | C# unit testing | xUnit, FluentAssertions, Bogus |
| 79 | Mocking | Moq, NSubstitute, test doubles |
| 80 | API integration testing | WebApplicationFactory, Respawn |
| 81 | Angular unit testing | Jasmine, Karma, Jest |
| 82 | Angular component testing | TestBed, Angular Testing Library |
| 83 | E2E testing | Cypress, cy.session, CI |
| 84 | Coverage, CI, mutation testing | Coverlet, GitHub Actions, Stryker |
Common Mistakes
Mistake 1 — Treating test suite as a one-time project (tests rot over time)
❌ Wrong — tests written once during feature development; not updated as code evolves; gradually all fail; team disables them.
✅ Correct — tests are maintained alongside code; updated in the same PR that changes the behaviour they test.
Mistake 2 — No test review in PRs (poor test quality slips through)
❌ Wrong — PR reviews only check production code; test code with no assertions or testing trivial things approved.
✅ Correct — review tests with same rigour as production code; check for meaningful assertions, correct test level, absence of anti-patterns.