Skip to content

test: raise Web coverage above 80% (issue #244) - #245

Merged
mpaulosky merged 2 commits into
devfrom
squad/244-raise-web-project-coverage-above-80
May 8, 2026
Merged

test: raise Web coverage above 80% (issue #244)#245
mpaulosky merged 2 commits into
devfrom
squad/244-raise-web-project-coverage-above-80

Conversation

@mpaulosky

Copy link
Copy Markdown
Owner

Working as Gimli (Tester)

Summary

Raises Web project line coverage from 69.5% → 81.5% (527/646 lines), clearing the 80% threshold required by issue #244.

Changes

New file

  • tests/Web.Tests/Infrastructure/Caching/BlogPostCacheServiceTests.cs — 11 tests covering BlogPostCacheService:
    • GetOrFetchAllAsync: L1 hit, L2 hit, corrupt L2 JSON fallback, full miss
    • GetOrFetchByIdAsync: L1 hit, L2 hit, corrupt L2 JSON fallback, full miss, null DB result
    • InvalidateAllAsync, InvalidateByIdAsync

Modified files

Added OperationCanceledException rethrow and unexpected Exception branch tests to:

  • CreateBlogPostHandlerTests
  • DeleteBlogPostHandlerTests
  • GetBlogPostsHandlerTests
  • EditBlogPostHandlerTests (both HandleEdit and HandleGetById paths)

Test Results

Project Before After
Web.Tests 127 tests 148 tests
Web.Tests.Bunit 65 tests 65 tests
Architecture.Tests 15 15
Domain.Tests 42 42

All 270 tests pass. Pre-push gate passed.

Coverage

Metric Before After
Line coverage 69.5% 81.5%
Covered lines 449 527
Coverable lines 646 646

Closes #244

- Add BlogPostCacheServiceTests covering all 4 methods of BlogPostCacheService:
  GetOrFetchAllAsync (L1 hit, L2 hit, corrupt L2, full miss),
  GetOrFetchByIdAsync (L1 hit, L2 hit, corrupt L2, full miss, null fetch),
  InvalidateAllAsync, InvalidateByIdAsync
- Add OperationCanceledException rethrow + unexpected Exception tests
  to CreateBlogPostHandler, DeleteBlogPostHandler, GetBlogPostsHandler,
  and EditBlogPostHandler (both Handle methods)
- Line coverage: 69.5% → 81.5% (527/646 lines)

Closes #244

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 8, 2026 00:02
@github-actions github-actions Bot added the squad Squad triage inbox — Lead will assign to a member label May 8, 2026
@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

🏗️ PR Added to Squad Triage Queue

This PR has been labeled with squad and added to the triage queue.

Next steps:

  • The squad Lead will review and assign to an appropriate team member
  • A squad:member label will be added after triage

If you know which squad member should handle this, you can add the appropriate squad:member label yourself.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Raises Web project test coverage above the 80% threshold required by issue #244 by adding focused unit tests around caching behavior and handler exception paths.

Changes:

  • Added new unit tests for BlogPostCacheService covering L1/L2 cache hits, corrupt L2 payload fallback, cache misses, and invalidation.
  • Expanded handler test suites to cover OperationCanceledException rethrow behavior and the generic “unexpected exception” failure path.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/Web.Tests/Infrastructure/Caching/BlogPostCacheServiceTests.cs New tests covering the two-tier blog post cache behavior (L1/L2/miss/corrupt payload/invalidate).
tests/Web.Tests/Handlers/GetBlogPostsHandlerTests.cs Adds tests for cancellation rethrow and unexpected exception result mapping.
tests/Web.Tests/Handlers/EditBlogPostHandlerTests.cs Adds tests for cancellation rethrow and unexpected exception handling in both edit and get-by-id paths.
tests/Web.Tests/Handlers/DeleteBlogPostHandlerTests.cs Adds tests for cancellation rethrow and unexpected exception result mapping.
tests/Web.Tests/Handlers/CreateBlogPostHandlerTests.cs Adds tests for cancellation rethrow and unexpected exception result mapping.

using System.Text.Json;

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
Comment on lines +19 to +54
private readonly MemoryCache _realLocalCache = new(new MemoryCacheOptions());
private readonly IDistributedCache _distributedCache = Substitute.For<IDistributedCache>();
private readonly BlogPostCacheService _sut;

public BlogPostCacheServiceTests()
{
_sut = new BlogPostCacheService(_realLocalCache, _distributedCache);
}

public void Dispose() => _realLocalCache.Dispose();

private static readonly JsonSerializerOptions JsonOpts = new(JsonSerializerDefaults.Web);

private static List<BlogPostDto> MakeDtos() =>
[
new(Guid.NewGuid(), "Title1", "Content1", "Author1", DateTime.UtcNow, null, false),
new(Guid.NewGuid(), "Title2", "Content2", "Author2", DateTime.UtcNow, null, true),
];

// ── GetOrFetchAllAsync ────────────────────────────────────────────────────

[Fact]
public async Task GetOrFetchAllAsync_L1Hit_ReturnsCachedListWithoutDistributedCall()
{
// Arrange
var cachedList = MakeDtos();
_realLocalCache.Set(BlogPostCacheKeys.All, cachedList);

var fetchCalled = false;
Task<IReadOnlyList<BlogPostDto>> fetch() { fetchCalled = true; return Task.FromResult<IReadOnlyList<BlogPostDto>>([]); }

// Act
var result = await _sut.GetOrFetchAllAsync(fetch, CancellationToken.None);

// Assert
result.Should().HaveCount(2);
@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Test Results Summary

304 tests  +21   303 ✅ +21   17s ⏱️ -2s
  6 suites ± 0     1 💤 ± 0 
  6 files   ± 0     0 ❌ ± 0 

Results for commit a7767df. ± Comparison against base commit 945d65a.

♻️ This comment has been updated with latest results.

@codecov

codecov Bot commented May 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.01%. Comparing base (945d65a) to head (930a138).

Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #245      +/-   ##
==========================================
+ Coverage   78.35%   83.01%   +4.65%     
==========================================
  Files          43       43              
  Lines         730      730              
  Branches      112      112              
==========================================
+ Hits          572      606      +34     
+ Misses        112       81      -31     
+ Partials       46       43       -3     

see 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mpaulosky
mpaulosky force-pushed the squad/244-raise-web-project-coverage-above-80 branch from 930a138 to 5277b66 Compare May 8, 2026 00:13
@mpaulosky

Copy link
Copy Markdown
Owner Author

✅ Aragorn — Lead Review: APPROVED

PR #245 — test: raise Web coverage above 80% (issue #244)

Note: GitHub prevents self-approval on this account. Review verdict posted as comment per tooling limitation.


Gate checks

Gate Status
CI fully green ✅ All 18 checks passing
Branch naming squad/* squad/244-raise-web-project-coverage-above-80
Base branch dev
Closes #244 in body
MERGEABLE
Copyright header on new file BlogPostCacheServiceTests.cs
No .squad/ files in diff
Tests authored (Gimli) ✅ 21 new tests
Production code touched ✅ None — test-only PR

Coverage

Before After
Line coverage 69.5% 81.5%
Covered lines 449 527

Coverage increases by 12 percentage points, clearing the 80% threshold required by #244. codecov/project and codecov/patch both pass. No coverage decrease — signal is green.

Copilot automated review

Copilot flagged two items — neither is a bug or security issue:

  1. Unused using Microsoft.Extensions.Options; (line 13, BlogPostCacheServiceTests.cs) — IDE0005 analyzer warning. With CodeAnalysisTreatWarningsAsErrors=false, not a hard error and CI passed. Recommend cleaning up before merge.
  2. Indentation inconsistency in BlogPostCacheServiceTests.cs — class members and method bodies are at column 0. Style concern, discretionary per playbook.

Both are cleanup items, not blockers. Ask Gimli to address on the branch before merge.

Architecture assessment

  • Handler cancellation tests correctly assert ThrowAsync<OperationCanceledException>() — confirms rethrow, not swallow ✅
  • Unexpected-exception tests assert result.Failure == true + result.Error == "An unexpected error occurred." — matches handler contract ✅
  • BlogPostCacheService tests use real MemoryCache for L1 (correct) + NSubstitute for IDistributedCache
  • All four cache paths covered: L1 hit, L2 hit, corrupt JSON fallback, full miss ✅
  • Null DB-result path covered for GetOrFetchByIdAsync
  • No VSA violations — pure test addition ✅

Verdict

✅ APPROVED (with optional cleanup requested). Structurally sound, architecturally correct, satisfies the coverage gate for #244.

Recommended pre-merge: Gimli removes the unused using Microsoft.Extensions.Options; and formats indentation in BlogPostCacheServiceTests.cs to match the rest of the test project. These are optional but clean.

@mpaulosky

Copy link
Copy Markdown
Owner Author

⚒️ Gimli — Tester Review: REQUEST CHANGES

PR #245 — test: raise Web coverage above 80% (issue #244)


What's good — a lot, actually

The handler exception-path additions are exactly what was needed:

  • All four handlers now have OperationCanceledException rethrow tests using the correct Func<Task> act = () => ... + ThrowAsync<OperationCanceledException>() pattern ✅
  • All four handlers now have unexpected Exception tests asserting result.Error.Should().Be("An unexpected error occurred.") — exact string match against the handler contract ✅
  • BlogPostCacheService uses a real MemoryCache for L1 (the right call — avoids the IMemoryCache.Set extension-method mock trap documented in our history) ✅
  • All four cache tiers covered: L1 hit, L2 hit, corrupt-JSON fallback, full miss ✅
  • Null DB-result path covered for GetOrFetchByIdAsync
  • IDisposable implemented to clean up the real MemoryCache
  • AAA comments present throughout ✅
  • File headers correct on all modified and new files ✅
  • Modified handler test files (Create, Delete, Edit, GetBlogPosts) all use correct tab indentation ✅

The coverage improvement is genuine — not gaming. These tests hit real production branches.


Blockers

🚨 BLOCKER 1 — BlogPostCacheServiceTests.cs: zero indentation (Critical Rule 8)

The new file has no indentation at all inside the class body. Fields, test methods, local variables, assertions — all flush-left at column 0. Critical Rule 8 requires tab indentation throughout. Every other test file in the project uses tabs correctly.

Example of what I'm seeing:

public class BlogPostCacheServiceTests : IDisposable
{
private readonly MemoryCache _realLocalCache = new(new MemoryCacheOptions());

Should be:

public class BlogPostCacheServiceTests : IDisposable
{
private readonly MemoryCache _realLocalCache = new(new MemoryCacheOptions());

🚨 BLOCKER 2 — Unused using Microsoft.Extensions.Options; (line 13)

BlogPostCacheServiceTests.cs imports Microsoft.Extensions.Options but nothing in the file uses it. Remove it.


Non-blockers (worth noting)

  • GetOrFetchAllAsync_L2Hit and GetOrFetchByIdAsync_L2Hit don't assert that fetch was NOT called. A fetchCalled = false flag + fetchCalled.Should().BeFalse() assertion (as done in the L1 hit tests) would make these airtight.
  • EditBlogPostHandler Edit path has no test for UpdateAsync throwing InvalidOperationException. Pre-existing gap — flag for follow-up.

Verdict

REQUEST CHANGES — Fix indentation and remove the unused using in BlogPostCacheServiceTests.cs. Logic is solid. Unblocks immediately with two formatting fixes.

…erviceTests

- Remove unused 'using Microsoft.Extensions.Options;'
- Re-indent entire file with tabs to match repo test-file style

Closes #245 blocker items

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mpaulosky pushed a commit that referenced this pull request May 8, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mpaulosky
mpaulosky force-pushed the squad/244-raise-web-project-coverage-above-80 branch from 2035ca2 to a7767df Compare May 8, 2026 00:31
@mpaulosky

Copy link
Copy Markdown
Owner Author

✅ Aragorn — Re-Review: APPROVED

PR #245 — test: raise Web coverage above 80% (issue #244)
Re-review after Sam/Boromir fix cycle

Note: GitHub prevents self-approval on this account. Review verdict posted as comment per tooling limitation.


Blocker resolution confirmed

Both of Gimli's CHANGES_REQUESTED blockers are resolved in the current HEAD (a7767df):

Blocker Status
🚨 BLOCKER 1: Zero indentation in BlogPostCacheServiceTests.cs ✅ Fixed — tab indentation throughout (fields, methods, assertions)
🚨 BLOCKER 2: Unused using Microsoft.Extensions.Options; ✅ Removed — only System.Text.Json and Microsoft.Extensions.Caching.Memory remain

Copilot's two inline review threads are both marked outdated — the fix commits superseded the original state that triggered those comments.


Gate compliance (re-verified)

Gate Status
CI fully green ✅ All checks passing (latest run post-fix)
Branch squad/* squad/244-raise-web-project-coverage-above-80
Base branch dev
Closes #244
MERGEABLE ✅ clean
Copyright header ✅ 7-line block format present
No .squad/ files in diff
Codecov ✅ 78.35% → 83.01% (+4.65%) — increase, no regression
Test results ✅ 303/304 pass, 0 failures

Verdict

✅ APPROVED — all blockers cleared, all gates green.

Ralph: you are clear to squash-merge PR #245.

@mpaulosky mpaulosky left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚒️ Gimli — Tester Re-Review: APPROVED ✅

PR #245 — test: raise Web coverage above 80% (issue #244)


Blocker Resolution

Both blockers from my previous REQUEST CHANGES verdict are fully resolved:

✅ BLOCKER 1 CLEARED — Tab indentation restored

BlogPostCacheServiceTests.cs now has correct tab indentation throughout — class fields, constructor, helper methods, and all 11 test methods. Every line inside the class body is properly indented. Matches project standard.

✅ BLOCKER 2 CLEARED — Unused using removed

using Microsoft.Extensions.Options; is gone. The two remaining usings are:

  • System.Text.Json — used by JsonSerializer, JsonSerializerOptions, JsonSerializerDefaults
  • Microsoft.Extensions.Caching.Memory — used by MemoryCache, MemoryCacheOptions

No dead imports. File is clean.


Re-Evaluation of BlogPostCacheServiceTests.cs

Full re-read confirms the file is correct and well-structured:

  • File header present and correctly formatted ✅
  • File-scoped namespace (namespace Web.Infrastructure.Caching;) ✅
  • AAA comments present on all 11 tests ✅
  • Real MemoryCache for L1 (correct — avoids the IMemoryCache.Set extension-method mock trap) ✅
  • NSubstitute for IDistributedCache
  • IDisposable implemented to dispose the real cache ✅
  • JsonSerializerOptions JsonOpts scoped as static readonly (efficient) ✅
  • All four cache tiers tested: L1 hit, L2 hit, corrupt JSON fallback, full miss ✅
  • Null DB-result path covered for GetOrFetchByIdAsync
  • Invalidation tests verify both L1 removal and distributed cache RemoveAsync
  • Handler exception-path tests (all four handlers) correct ✅

Standing Non-Blockers (carry-forward, no action needed now)

  • L2 hit tests (GetOrFetchAllAsync_L2Hit, GetOrFetchByIdAsync_L2Hit) don't assert the fetch delegate was NOT called. Airtight but functional without it. Flag for follow-up.
  • EditBlogPostHandler Edit path missing a test for UpdateAsync throwing InvalidOperationException. Pre-existing gap — tell Aragorn.

Verdict

✅ APPROVED — test review is clear.

Both blockers resolved, CI green (304 tests, 0 failures), coverage 83.01% → well above the 80% gate required by #244. This is ready to merge.

@mpaulosky
mpaulosky merged commit 0a5e4e2 into dev May 8, 2026
25 of 32 checks passed
@mpaulosky
mpaulosky deleted the squad/244-raise-web-project-coverage-above-80 branch May 8, 2026 00:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

squad Squad triage inbox — Lead will assign to a member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Sprint 14] Raise Web project coverage above 80%

2 participants