Part 8 Completion — Testing Summary and Part 9 Preview

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)
Note: The testing anti-patterns to actively avoid in the BlogApp’s test suite: testing the framework (asserting that EF Core saves an entity — EF Core is already tested by Microsoft), over-mocking (mocking so many dependencies that the test only tests mock configuration), testing implementation not behaviour (verifying which private methods were called rather than what the public behaviour produced), and assertion-free tests (tests that call methods but make no assertions — providing 100% execution coverage and 0% bug detection).
Tip: The “boy scout rule” applies to tests: always leave the test suite better than you found it. When you fix a bug, add a regression test. When you add a feature, add tests at the appropriate level. When you see a test with a vague assertion (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.
Warning: Part 9 (Capstone: Classified Website) uses Clean Architecture with CQRS and MediatR — a significantly more complex structure than the BlogApp’s service-repository pattern. The testing approaches from Part 8 all apply, but with adaptations: unit testing MediatR handlers instead of services, integration testing the command/query pipeline, and testing domain events. Plan to spend time in Part 9 adapting the testing patterns to the Clean Architecture structure before implementing features.

🎓 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.

🧠 Test Yourself

The BlogApp has 82% line coverage. A developer adds a new PostAnalyticsService with 500 lines and zero tests. What happens to overall coverage?