Skip to content

Support Contract/Snapshot Testing using Verify#102

Merged
foxminchan merged 1 commit into
mainfrom
test/contract-testing
Aug 4, 2025
Merged

Support Contract/Snapshot Testing using Verify#102
foxminchan merged 1 commit into
mainfrom
test/contract-testing

Conversation

@foxminchan

@foxminchan foxminchan commented Aug 4, 2025

Copy link
Copy Markdown
Owner

Pull Request Description

Checklist

  • My code follows the DDD principles
  • I've used the latest C# features and idioms
  • I've added/updated unit tests for business logic
  • Service boundaries are maintained (no cross-service direct dependencies)
  • Repository pattern is used for data access
  • Domain Events are used for cross-service communication
  • I've registered new services in AppHost project (if applicable)
  • I've updated both entities and DTOs (if applicable)

Summary by CodeRabbit

  • New Features

    • Introduced snapshot-based contract testing across multiple services to ensure message and event structure consistency.
    • Added a shared snapshot testing base to enable deterministic and reliable contract verification in unit tests.
    • Updated documentation to reflect the inclusion of contract tests in the testing strategy.
  • Bug Fixes

    • Improved asynchronous test assertions to ensure proper task handling in chat command tests.
  • Chores

    • Updated and streamlined test dependencies, replacing legacy test frameworks with a unified snapshot testing package.
    • Added and updated package versions for improved compatibility and maintenance.

@netlify

netlify Bot commented Aug 4, 2025

Copy link
Copy Markdown

Deploy Preview for bookwormdev canceled.

Name Link
🔨 Latest commit 05019ec
🔍 Latest deploy log https://app.netlify.com/projects/bookwormdev/deploys/68909c1180132700080ad0d8

@coderabbitai

coderabbitai Bot commented Aug 4, 2025

Copy link
Copy Markdown

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This update introduces snapshot-based contract testing across multiple service unit tests by adding a new SnapshotTestBase class. Test projects are refactored to use the Verify.TUnit package, replacing MassTransit.TestFramework. Numerous test classes now inherit from SnapshotTestBase, and new snapshot JSON files are added to verify message contracts. Minor dependency and documentation updates are included.

Changes

Cohort / File(s) Change Summary
Snapshot Testing Infrastructure
tests/BookWorm.Common/SnapshotTestBase.cs
Introduces SnapshotTestBase class for deterministic snapshot testing, including GUID/DateTime scrubbing and dynamic snapshot directory resolution.
Test Project Package Updates & Shared Base Inclusion
src/Services/Basket/BookWorm.Basket.UnitTests/BookWorm.Basket.UnitTests.csproj, src/Services/Catalog/BookWorm.Catalog.UnitTests/BookWorm.Catalog.UnitTests.csproj, src/Services/Finance/BookWorm.Finance.UnitTests/BookWorm.Finance.UnitTests.csproj, src/Services/Notification/BookWorm.Notification.UnitTests/BookWorm.Notification.UnitTests.csproj, src/Services/Ordering/BookWorm.Ordering.UnitTests/BookWorm.Ordering.UnitTests.csproj, src/Services/Rating/BookWorm.Rating.UnitTests/BookWorm.Rating.UnitTests.csproj
Replace MassTransit.TestFramework with Verify.TUnit and link in SnapshotTestBase.cs for snapshot testing support.
Basket Service Unit Tests & Snapshots
src/Services/Basket/BookWorm.Basket.UnitTests/Consumers/PlaceOrderConsumerTests.cs, src/Services/Basket/BookWorm.Basket.UnitTests/Snapshots/*
Refactor tests to inherit from SnapshotTestBase, add contract verification via snapshots, and introduce new test for input contract. New snapshot files added for contract validation.
Catalog Service Unit Tests & Snapshots
src/Services/Catalog/BookWorm.Catalog.UnitTests/Consumers/FeedbackCreatedConsumerTests.cs, src/Services/Catalog/BookWorm.Catalog.UnitTests/Consumers/FeedbackDeletedConsumerTests.cs, src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/*
Tests updated to inherit SnapshotTestBase and add snapshot-based contract validation. New test methods and snapshot files added to verify event contracts.
Finance Service Unit Tests & Snapshots
src/Services/Finance/BookWorm.Finance.UnitTests/OrderStateMachineTests.cs, src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/*
Test class updated to inherit SnapshotTestBase, add snapshot verification for events and commands, refactor/rename one test, and add multiple snapshot files for contract validation.
Notification Service Unit Tests & Snapshots
src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CancelOrderConsumerTests.cs, src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CleanUpSentEmailConsumerTests.cs, src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CompleteOrderConsumerTests.cs, src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/PlaceOrderConsumerTests.cs, src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/ResendErrorEmailConsumerTests.cs, src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/*
Test classes inherit SnapshotTestBase and add snapshot verification for commands/events. Numerous new snapshot files added for contract validation.
Ordering Service Unit Tests & Snapshots
src/Services/Ordering/BookWorm.Ordering.UnitTests/Consumers/DeleteBasketCompleteConsumerTests.cs, src/Services/Ordering/BookWorm.Ordering.UnitTests/Consumers/DeleteBasketFailedConsumerTests.cs, src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/*
Test classes updated to inherit SnapshotTestBase and add snapshot verification for commands. New snapshot files added for contract validation.
Rating Service Unit Tests & Snapshots
src/Services/Rating/BookWorm.Rating.UnitTests/Consumers/BookUpdatedRatingFailedConsumerTests.cs, src/Services/Rating/BookWorm.Rating.UnitTests/Snapshots/*
Test class updated to inherit SnapshotTestBase and add snapshot verification for events. New snapshot files added for contract validation.
Dependency and Version Updates
Directory.Packages.props, Versions.props, src/Services/Scheduler/BookWorm.Scheduler.UnitTests/BookWorm.Scheduler.UnitTests.csproj
Update package versions, add/remove dependencies, and remove obsolete test framework references.
Miscellaneous Test Fix
src/Services/Chat/BookWorm.Chat.UnitTests/Features/Cancel/CancelChatCommandTests.cs
Minor fix: switch from .Result to await for asynchronous test assertions.
Documentation
README.md
Add checklist item for contract tests in the testing strategy section.

Sequence Diagram(s)

sequenceDiagram
    participant TestMethod
    participant SnapshotTestBase
    participant Verifier
    participant SnapshotsDir

    TestMethod->>SnapshotTestBase: Call VerifySnapshot(message/command/event)
    SnapshotTestBase->>Verifier: Configure scrubbers, start verification
    Verifier->>SnapshotTestBase: Request snapshot directory
    SnapshotTestBase->>SnapshotsDir: Resolve Snapshots/ directory (traverse up to project root)
    SnapshotsDir-->>SnapshotTestBase: Return path
    Verifier->>SnapshotsDir: Save or compare snapshot JSON
    SnapshotsDir-->>Verifier: Snapshot result
    Verifier-->>TestMethod: Verification result (pass/fail)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

Suggested labels

.NET

Poem

Snapshots bloom in test arrays,
GUIDs and dates now scrubbed away.
Contracts frozen, schemas tight—
Each event and command in JSON light.
With every test, our trust expands,
For structure’s safe in snapshot lands!
📝✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d2cfb9 and 05019ec.

📒 Files selected for processing (63)
  • Directory.Packages.props (2 hunks)
  • README.md (1 hunks)
  • Versions.props (1 hunks)
  • src/Services/Basket/BookWorm.Basket.UnitTests/BookWorm.Basket.UnitTests.csproj (1 hunks)
  • src/Services/Basket/BookWorm.Basket.UnitTests/Consumers/PlaceOrderConsumerTests.cs (4 hunks)
  • src/Services/Basket/BookWorm.Basket.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenPlaceOrderCommand_ThenShouldVerifyInputContract.verified.json (1 hunks)
  • src/Services/Basket/BookWorm.Basket.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenValidPlaceOrderCommand_WhenBasketDeleteFails_ThenShouldPublishFailedEvent.verified.json (1 hunks)
  • src/Services/Basket/BookWorm.Basket.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenValidPlaceOrderCommand_WhenBasketDeleteSucceeds_ThenShouldPublishCompleteEvent.verified.json (1 hunks)
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/BookWorm.Catalog.UnitTests.csproj (1 hunks)
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Consumers/FeedbackCreatedConsumerTests.cs (4 hunks)
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Consumers/FeedbackDeletedConsumerTests.cs (4 hunks)
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackCreatedConsumerTests.GivenFeedbackCreatedEventWithNonExistingBook_WhenHandling_ThenShouldPublishFailedEvent.verified.json (1 hunks)
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackCreatedConsumerTests.GivenFeedbackCreatedIntegrationEvent_ThenShouldVerifyInputContract.verified.json (1 hunks)
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackCreatedConsumerTests.GivenValidFeedbackCreatedEvent_WhenHandling_ThenShouldUpdateBookRating.verified.json (1 hunks)
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackDeletedConsumerTests.GivenFeedbackDeletedEventWithNonExistingBook_WhenHandling_ThenShouldReturnGracefully.verified.json (1 hunks)
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackDeletedConsumerTests.GivenFeedbackDeletedIntegrationEvent_ThenShouldVerifyInputContract.verified.json (1 hunks)
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackDeletedConsumerTests.GivenValidFeedbackDeletedEvent_WhenHandling_ThenShouldRemoveBookRating.verified.json (1 hunks)
  • src/Services/Chat/BookWorm.Chat.UnitTests/Features/Cancel/CancelChatCommandTests.cs (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/BookWorm.Finance.UnitTests.csproj (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/OrderStateMachineTests.cs (11 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenBasketDeletedCompleteIntegrationEvent_WhenConsuming_ThenShouldPublishDeleteBasketCompleteCommand.verified.json (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenBasketDeletedFailedIntegrationEvent_WhenConsuming_ThenShouldPublishDeleteBasketFailedCommand.verified.json (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderStatusChangedToCancelEvent_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand_email=example@email.com_fullName=null.verified.json (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderStatusChangedToCancelEvent_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand_email=null_fullName=John Doe.verified.json (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderStatusChangedToCancelEvent_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand_email=null_fullName=null.verified.json (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderTimeout_WhenRetryCountLessThanMax_ThenShouldRetryOrderProcessing.verified.json (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderTimeout_WhenRetryCountLessThanMax_ThenShouldRetryOrderProcessing_OutputCommand.verified.json (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderTimeout_WhenRetryCountReachesMax_ThenShouldTransitionToFailedAndCancel.verified.json (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderTimeout_WhenRetryCountReachesMax_ThenShouldTransitionToFailedAndCancel_OutputCommand.verified.json (1 hunks)
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenUserCheckedOutIntegrationEvent_WhenConsuming_ThenShouldCreateOrderStateAndPublishPlaceOrderCommand.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/BookWorm.Notification.UnitTests.csproj (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CancelOrderConsumerTests.cs (5 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CleanUpSentEmailConsumerTests.cs (4 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CompleteOrderConsumerTests.cs (5 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/PlaceOrderConsumerTests.cs (5 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/ResendErrorEmailConsumerTests.cs (4 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CancelOrderConsumerTests.GivenCancelOrderCommandWithEmptyEmail_WhenHandling_ThenShouldNotSendEmail.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CancelOrderConsumerTests.GivenCancelOrderCommandWithNullEmail_WhenHandling_ThenShouldNotSendEmail.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CancelOrderConsumerTests.GivenValidCancelOrderCommand_WhenHandling_ThenShouldSendEmail.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CleanUpSentEmailConsumerTests.GivenNoSentEmailsExist_WhenHandlingCleanUpEvent_ThenShouldLogNoEmailsFound.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CleanUpSentEmailConsumerTests.GivenSentEmailsExist_WhenHandlingCleanUpEvent_ThenShouldDeleteEmailsAndSaveChanges.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CompleteOrderConsumerTests.GivenCompleteOrderCommandWithEmptyEmail_WhenHandling_ThenShouldNotSendEmail.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CompleteOrderConsumerTests.GivenCompleteOrderCommandWithNullEmail_WhenHandling_ThenShouldNotSendEmail.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CompleteOrderConsumerTests.GivenValidCompleteOrderCommand_WhenHandling_ThenShouldSendEmail.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenPlaceOrderCommandWithEmptyEmail_WhenHandling_ThenShouldNotSendEmail.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenPlaceOrderCommandWithNullEmail_WhenHandling_ThenShouldNotSendEmail.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenValidPlaceOrderCommand_WhenHandling_ThenShouldSendEmail.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/ResendErrorEmailConsumerTests.GivenEmailsExist_WhenHandlingResendEvent_ThenShouldResendAllEmails.verified.json (1 hunks)
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/ResendErrorEmailConsumerTests.GivenNoEmailsExist_WhenHandlingResendEvent_ThenShouldCompleteWithoutSending.verified.json (1 hunks)
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/BookWorm.Ordering.UnitTests.csproj (1 hunks)
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Consumers/DeleteBasketCompleteConsumerTests.cs (5 hunks)
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Consumers/DeleteBasketFailedConsumerTests.cs (4 hunks)
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketCompleteConsumerTests.GivenMultipleCommands_WhenConsumed_ThenShouldProcessAllSuccessfully.verified.json (1 hunks)
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketCompleteConsumerTests.GivenValidCommand_WhenConsumed_ThenShouldCompleteSuccessfully.verified.json (1 hunks)
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketCompleteConsumerTests.GivenValidCommand_WhenConsumed_ThenShouldLogInformation.verified.json (1 hunks)
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketFailedConsumerTests.GivenDeleteBasketFailedCommandWithNonExistingOrder_WhenHandling_ThenShouldReturnGracefully.verified.json (1 hunks)
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketFailedConsumerTests.GivenValidDeleteBasketFailedCommand_WhenHandling_ThenShouldDeleteOrder.verified.json (1 hunks)
  • src/Services/Rating/BookWorm.Rating.UnitTests/BookWorm.Rating.UnitTests.csproj (1 hunks)
  • src/Services/Rating/BookWorm.Rating.UnitTests/Consumers/BookUpdatedRatingFailedConsumerTests.cs (4 hunks)
  • src/Services/Rating/BookWorm.Rating.UnitTests/Snapshots/BookUpdatedRatingFailedConsumerTests.GivenFailedRatingEventWithNonExistingFeedback_WhenHandling_ThenShouldReturnGracefully.verified.json (1 hunks)
  • src/Services/Rating/BookWorm.Rating.UnitTests/Snapshots/BookUpdatedRatingFailedConsumerTests.GivenValidFailedRatingEvent_WhenHandling_ThenShouldDeleteFeedback.verified.json (1 hunks)
  • src/Services/Scheduler/BookWorm.Scheduler.UnitTests/BookWorm.Scheduler.UnitTests.csproj (0 hunks)
  • tests/BookWorm.Common/SnapshotTestBase.cs (1 hunks)
💤 Files with no reviewable changes (1)
  • src/Services/Scheduler/BookWorm.Scheduler.UnitTests/BookWorm.Scheduler.UnitTests.csproj
✅ Files skipped from review due to trivial changes (16)
  • src/Services/Notification/BookWorm.Notification.UnitTests/BookWorm.Notification.UnitTests.csproj
  • src/Services/Basket/BookWorm.Basket.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenValidPlaceOrderCommand_WhenBasketDeleteFails_ThenShouldPublishFailedEvent.verified.json
  • src/Services/Rating/BookWorm.Rating.UnitTests/BookWorm.Rating.UnitTests.csproj
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/BookWorm.Ordering.UnitTests.csproj
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketFailedConsumerTests.GivenValidDeleteBasketFailedCommand_WhenHandling_ThenShouldDeleteOrder.verified.json
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketFailedConsumerTests.GivenDeleteBasketFailedCommandWithNonExistingOrder_WhenHandling_ThenShouldReturnGracefully.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenValidPlaceOrderCommand_WhenHandling_ThenShouldSendEmail.verified.json
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenBasketDeletedFailedIntegrationEvent_WhenConsuming_ThenShouldPublishDeleteBasketFailedCommand.verified.json
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenUserCheckedOutIntegrationEvent_WhenConsuming_ThenShouldCreateOrderStateAndPublishPlaceOrderCommand.verified.json
  • src/Services/Basket/BookWorm.Basket.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenValidPlaceOrderCommand_WhenBasketDeleteSucceeds_ThenShouldPublishCompleteEvent.verified.json
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackDeletedConsumerTests.GivenFeedbackDeletedIntegrationEvent_ThenShouldVerifyInputContract.verified.json
  • src/Services/Finance/BookWorm.Finance.UnitTests/BookWorm.Finance.UnitTests.csproj
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenBasketDeletedCompleteIntegrationEvent_WhenConsuming_ThenShouldPublishDeleteBasketCompleteCommand.verified.json
  • src/Services/Basket/BookWorm.Basket.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenPlaceOrderCommand_ThenShouldVerifyInputContract.verified.json
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackCreatedConsumerTests.GivenFeedbackCreatedIntegrationEvent_ThenShouldVerifyInputContract.verified.json
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackCreatedConsumerTests.GivenValidFeedbackCreatedEvent_WhenHandling_ThenShouldUpdateBookRating.verified.json
🚧 Files skipped from review as they are similar to previous changes (46)
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/BookWorm.Catalog.UnitTests.csproj
  • README.md
  • Versions.props
  • src/Services/Chat/BookWorm.Chat.UnitTests/Features/Cancel/CancelChatCommandTests.cs
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderStatusChangedToCancelEvent_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand_email=null_fullName=John Doe.verified.json
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Consumers/FeedbackDeletedConsumerTests.cs
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderStatusChangedToCancelEvent_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand_email=null_fullName=null.verified.json
  • src/Services/Rating/BookWorm.Rating.UnitTests/Snapshots/BookUpdatedRatingFailedConsumerTests.GivenValidFailedRatingEvent_WhenHandling_ThenShouldDeleteFeedback.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CleanUpSentEmailConsumerTests.GivenNoSentEmailsExist_WhenHandlingCleanUpEvent_ThenShouldLogNoEmailsFound.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CompleteOrderConsumerTests.GivenCompleteOrderCommandWithNullEmail_WhenHandling_ThenShouldNotSendEmail.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CleanUpSentEmailConsumerTests.GivenSentEmailsExist_WhenHandlingCleanUpEvent_ThenShouldDeleteEmailsAndSaveChanges.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CompleteOrderConsumerTests.GivenCompleteOrderCommandWithEmptyEmail_WhenHandling_ThenShouldNotSendEmail.verified.json
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketCompleteConsumerTests.GivenMultipleCommands_WhenConsumed_ThenShouldProcessAllSuccessfully.verified.json
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackCreatedConsumerTests.GivenFeedbackCreatedEventWithNonExistingBook_WhenHandling_ThenShouldPublishFailedEvent.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CompleteOrderConsumerTests.GivenValidCompleteOrderCommand_WhenHandling_ThenShouldSendEmail.verified.json
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Consumers/FeedbackCreatedConsumerTests.cs
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackDeletedConsumerTests.GivenValidFeedbackDeletedEvent_WhenHandling_ThenShouldRemoveBookRating.verified.json
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderTimeout_WhenRetryCountReachesMax_ThenShouldTransitionToFailedAndCancel_OutputCommand.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CleanUpSentEmailConsumerTests.cs
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketCompleteConsumerTests.GivenValidCommand_WhenConsumed_ThenShouldCompleteSuccessfully.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/ResendErrorEmailConsumerTests.GivenNoEmailsExist_WhenHandlingResendEvent_ThenShouldCompleteWithoutSending.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CancelOrderConsumerTests.cs
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CancelOrderConsumerTests.GivenValidCancelOrderCommand_WhenHandling_ThenShouldSendEmail.verified.json
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketCompleteConsumerTests.GivenValidCommand_WhenConsumed_ThenShouldLogInformation.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CompleteOrderConsumerTests.cs
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Consumers/DeleteBasketCompleteConsumerTests.cs
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/ResendErrorEmailConsumerTests.GivenEmailsExist_WhenHandlingResendEvent_ThenShouldResendAllEmails.verified.json
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderTimeout_WhenRetryCountReachesMax_ThenShouldTransitionToFailedAndCancel.verified.json
  • src/Services/Basket/BookWorm.Basket.UnitTests/BookWorm.Basket.UnitTests.csproj
  • src/Services/Basket/BookWorm.Basket.UnitTests/Consumers/PlaceOrderConsumerTests.cs
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderTimeout_WhenRetryCountLessThanMax_ThenShouldRetryOrderProcessing_OutputCommand.verified.json
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderStatusChangedToCancelEvent_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand_email=[email protected]_fullName=null.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenPlaceOrderCommandWithNullEmail_WhenHandling_ThenShouldNotSendEmail.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CancelOrderConsumerTests.GivenCancelOrderCommandWithEmptyEmail_WhenHandling_ThenShouldNotSendEmail.verified.json
  • Directory.Packages.props
  • src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderTimeout_WhenRetryCountLessThanMax_ThenShouldRetryOrderProcessing.verified.json
  • src/Services/Finance/BookWorm.Finance.UnitTests/OrderStateMachineTests.cs
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenPlaceOrderCommandWithEmptyEmail_WhenHandling_ThenShouldNotSendEmail.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CancelOrderConsumerTests.GivenCancelOrderCommandWithNullEmail_WhenHandling_ThenShouldNotSendEmail.verified.json
  • src/Services/Catalog/BookWorm.Catalog.UnitTests/Snapshots/FeedbackDeletedConsumerTests.GivenFeedbackDeletedEventWithNonExistingBook_WhenHandling_ThenShouldReturnGracefully.verified.json
  • src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/PlaceOrderConsumerTests.cs
  • tests/BookWorm.Common/SnapshotTestBase.cs
  • src/Services/Ordering/BookWorm.Ordering.UnitTests/Consumers/DeleteBasketFailedConsumerTests.cs
  • src/Services/Rating/BookWorm.Rating.UnitTests/Consumers/BookUpdatedRatingFailedConsumerTests.cs
  • src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/ResendErrorEmailConsumerTests.cs
  • src/Services/Rating/BookWorm.Rating.UnitTests/Snapshots/BookUpdatedRatingFailedConsumerTests.GivenFailedRatingEventWithNonExistingFeedback_WhenHandling_ThenShouldReturnGracefully.verified.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Style
  • GitHub Check: Analyzers
  • GitHub Check: Security Scan
  • GitHub Check: Build and analyze
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch test/contract-testing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@foxminchan foxminchan self-assigned this Aug 4, 2025
@foxminchan foxminchan linked an issue Aug 4, 2025 that may be closed by this pull request
@foxminchan foxminchan changed the title test: Support #101 Contract/Snapshot Testing using Verify Support Contract/Snapshot Testing using Verify Aug 4, 2025
@foxminchan
foxminchan force-pushed the test/contract-testing branch from 6fb252d to 4d2cfb9 Compare August 4, 2025 11:19
@foxminchan
foxminchan marked this pull request as ready for review August 4, 2025 11:19
Copilot AI review requested due to automatic review settings August 4, 2025 11:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces contract/snapshot testing capabilities using the Verify library to ensure API consistency across the BookWorm microservices. The changes establish a standardized approach to verifying message contracts and data structures in integration event handlers and consumers.

Key changes include:

  • Addition of a shared SnapshotTestBase class that provides contract testing infrastructure with deterministic data scrubbing
  • Migration from MassTransit.TestFramework to Verify.TUnit for enhanced snapshot testing capabilities
  • Implementation of contract verification tests across all service boundaries to prevent breaking changes

Reviewed Changes

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

Show a summary per file
File Description
tests/BookWorm.Common/SnapshotTestBase.cs New base class providing snapshot testing infrastructure with GUID/DateTime scrubbing
Multiple service test projects Updated to inherit from SnapshotTestBase and include contract verification tests
Directory.Packages.props Added Verify.TUnit package and removed MassTransit.TestFramework dependency
Snapshot files (.verified.json) Generated contract snapshots for all integration events and commands
Consumer test files Enhanced with contract verification logic to ensure message structure consistency
Comments suppressed due to low confidence (1)

src/Services/Finance/BookWorm.Finance.UnitTests/OrderStateMachineTests.cs:647

  • Missing semicolon after the VerifySnapshot method call.
        await VerifySnapshot(retryCommand)

var content = builder.ToString();

// Scrub GUIDs to make snapshots deterministic
var scrubbedContent = GuidRegex().Replace(content, "Guid_Scrubbed");

Copilot AI Aug 4, 2025

Copy link

Choose a reason for hiding this comment

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

The replacement text "Guid_Scrubbed" is inconsistent with the actual snapshot files which show "Guid_1", "Guid_2", etc. This suggests the scrubber may not be working as intended or the snapshots were generated differently.

Suggested change
var scrubbedContent = GuidRegex().Replace(content, "Guid_Scrubbed");
var guidMap = new Dictionary<string, string>();
int guidCounter = 1;
var scrubbedContent = GuidRegex().Replace(content, match =>
{
var guid = match.Value;
if (!guidMap.TryGetValue(guid, out var replacement))
{
replacement = $"Guid_{guidCounter++}";
guidMap[guid] = replacement;
}
return replacement;
});

Copilot uses AI. Check for mistakes.
var scrubbedContent = GuidRegex().Replace(content, "Guid_Scrubbed");

// Scrub DateTime values to make snapshots deterministic
scrubbedContent = DateTimeRegex().Replace(scrubbedContent, "DateTime_Scrubbed");

Copilot AI Aug 4, 2025

Copy link

Choose a reason for hiding this comment

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

The replacement text "DateTime_Scrubbed" is inconsistent with the actual snapshot files which show "DateTime_1", "DateTime_2", etc. This suggests the scrubber may not be working as intended or the snapshots were generated differently.

Suggested change
scrubbedContent = DateTimeRegex().Replace(scrubbedContent, "DateTime_Scrubbed");
int dateTimeCounter = 1;
scrubbedContent = DateTimeRegex().Replace(
scrubbedContent,
match => $"DateTime_{dateTimeCounter++}"
);

Copilot uses AI. Check for mistakes.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

♻️ Duplicate comments (5)
src/Services/Catalog/BookWorm.Catalog.UnitTests/BookWorm.Catalog.UnitTests.csproj (2)

9-10: Same concern on unpinned Verify.TUnit version – see earlier remark in Rating unit-tests project.


12-15: Shared utility should be referenced, not linked – identical feedback as given for Rating unit-tests.

src/Services/Finance/BookWorm.Finance.UnitTests/BookWorm.Finance.UnitTests.csproj (2)

8-9: Unpinned Verify.TUnit version – same recommendation to add an explicit version or central package management.


11-14: Linked file maintenance issue – see earlier advice to replace compile linking with a shared testing project reference.

src/Services/Rating/BookWorm.Rating.UnitTests/Snapshots/BookUpdatedRatingFailedConsumerTests.GivenValidFailedRatingEvent_WhenHandling_ThenShouldDeleteFeedback.verified.json (1)

1-5: Mirror suggestions from sibling snapshot

Apply the same newline/placeholder consistency tweaks here to keep all rating snapshots uniform.

🧹 Nitpick comments (28)
README.md (1)

44-45: Keep checklist tense consistent

All items above use “Conducted / Implemented / Established”. New bullet could mirror that (“Implemented contract tests ✅”) to stay uniform.

src/Services/Notification/BookWorm.Notification.UnitTests/BookWorm.Notification.UnitTests.csproj (1)

12-15: Relative include path is brittle—consider Shared Test project

Deep ..\..\..\..\ hops break quickly when folders move. Two alternatives:

  1. Create a small BookWorm.Common.Tests project and reference it via <ProjectReference> from every unit-test project.
  2. If you keep a link, define a MSBuild property ($(CommonTestsDir)) once and consume it, e.g.:
<PropertyGroup>
  <CommonTestsDir>$(SolutionDir)tests\BookWorm.Common\</CommonTestsDir>
</PropertyGroup>
<ItemGroup>
  <Compile Include="$(CommonTestsDir)SnapshotTestBase.cs" Link="SnapshotTestBase.cs" />
</ItemGroup>

This hardens maintainability across the repo.

src/Services/Rating/BookWorm.Rating.UnitTests/BookWorm.Rating.UnitTests.csproj (2)

9-10: Pin the Verify.TUnit package version for deterministic builds

Leaving the version implicit allows NuGet to float to newer releases, which can silently break or invalidate existing snapshots.
Specify an explicit version or manage the package centrally via Directory.Packages.props to lock the tool-chain across all pipelines.


12-15: Prefer a shared test utility project over file linking

Linking SnapshotTestBase.cs into each test project creates duplication and maintenance overhead.
Extract tests/BookWorm.Common into a .csproj (e.g., BookWorm.Testing.Shared) and reference it, keeping a single source of truth and avoiding compile-item drift.

src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CancelOrderConsumerTests.GivenValidCancelOrderCommand_WhenHandling_ThenShouldSendEmail.verified.json (1)

1-8: Confirm decimal culture & newline for snapshot stability

Looks solid, but two tiny details can help avoid flaky diffs:

  1. 99.99 – ensure the serializer is forced to InvariantCulture so commas/periods don’t swap on different locales.
  2. There’s no terminating newline after } (and the file carries a UTF-8 BOM). Adding a final LF and stripping the BOM keeps Git diffs cleaner and makes some *nix tooling happier.

Nothing blocking, just polish.

src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/ResendErrorEmailConsumerTests.GivenEmailsExist_WhenHandlingResendEvent_ThenShouldResendAllEmails.verified.json (1)

1-4: Snapshot captures only Id/CreationDate – intentional?

If the integration event ever grows additional fields, this minimal snapshot won’t alert us. Consider snapshotting the full contract (even if most values are placeholders) to future-proof the test.

Not urgent, but worth double-checking the test intent.

src/Services/Basket/BookWorm.Basket.UnitTests/BookWorm.Basket.UnitTests.csproj (1)

9-15: Pin Verify.TUnit version & include <PrivateAssets>

Leaving the version floating can unexpectedly break CI when Verify releases a major version. Recommend pinning the same version used elsewhere and shielding it from production transitive flow:

-    <PackageReference Include="Verify.TUnit" />
+    <PackageReference Include="Verify.TUnit" Version="30.5.0" PrivateAssets="all" />

Keeps test deps deterministic and prevents them leaking into consumer projects.

src/Services/Rating/BookWorm.Rating.UnitTests/Snapshots/BookUpdatedRatingFailedConsumerTests.GivenFailedRatingEventWithNonExistingFeedback_WhenHandling_ThenShouldReturnGracefully.verified.json (1)

1-5: Add trailing newline & check placeholder consistency

Same minor housekeeping as other snapshots:

  1. Append a trailing \n to avoid diff noise.
  2. Confirm Guid_1 vs Guid_2 mapping matches deterministic scrub logic (first placeholder should always map to the same property across snapshots).

Purely cosmetic.

src/Services/Ordering/BookWorm.Ordering.UnitTests/Snapshots/DeleteBasketFailedConsumerTests.GivenDeleteBasketFailedCommandWithNonExistingOrder_WhenHandling_ThenShouldReturnGracefully.verified.json (1)

1-8: Minor formatting inconsistency on monetary value
The amount is expressed as 200.00, whereas other snapshots (see Finance) serialize as 100.0. While Verify will still match, a uniform decimal formatter (e.g. JsonSerializerOptions.NumberHandling or a custom MoneyJsonConverter) would keep all money fields at a consistent 0.00 precision and eliminate noisy diffs.

src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CancelOrderConsumerTests.GivenCancelOrderCommandWithEmptyEmail_WhenHandling_ThenShouldNotSendEmail.verified.json (1)

1-8: Placeholder data looks safe; consider neutral full-name
"John Doe" is fine for non-PII test data, but several teams prefer obviously fake names like "Example User" to avoid confusion with production dumps. No blocker—just a style consideration.

src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderStatusChangedToCancelEvent_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand_email=null_fullName=null.verified.json (1)

1-7: Align monetary serialization to two-decimal precision
"TotalMoney": 100.0 deviates from the 250.00 / 200.00 format used elsewhere. Update the snapshot (or, preferably, introduce a custom JSON converter for the Money value object) so every amount serializes with exactly two fractional digits.

-  "TotalMoney": 100.0,
+  "TotalMoney": 100.00,
src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenPlaceOrderCommandWithEmptyEmail_WhenHandling_ThenShouldNotSendEmail.verified.json (1)

1-1: Strip the UTF-8 BOM to avoid noisy diffs

The leading “” (U+FEFF) means the file was saved with a BOM. Our snapshot files are treated as pure data and the BOM has repeatedly caused false-positive diffs on Windows vs *nix CI agents.

-{
+{
src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CleanUpSentEmailConsumerTests.GivenSentEmailsExist_WhenHandlingCleanUpEvent_ThenShouldDeleteEmailsAndSaveChanges.verified.json (2)

1-1: Remove UTF-8 BOM

Same BOM issue as noted in the previous snapshot.


2-4: Snapshot may be too narrow

Only Id and CreationDate are captured. If the consumer mutates additional fields (e.g., DeletionDate, IsDeleted), the test will miss regressions.

Consider expanding the snapshot to include every column that represents the persisted state after cleanup.

src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/CompleteOrderConsumerTests.GivenValidCompleteOrderCommand_WhenHandling_ThenShouldSendEmail.verified.json (1)

1-1: Remove UTF-8 BOM

Applies here as well.

src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderTimeout_WhenRetryCountReachesMax_ThenShouldTransitionToFailedAndCancel_OutputCommand.verified.json (2)

1-1: Remove UTF-8 BOM

Consistent with the other snapshot files.


2-8: Placeholder email differs from other snapshots

Here the address is [email protected]; elsewhere we use [email protected]. Using a single canonical test address avoids accidental semantic differences when snapshots are programmatically compared.

Recommend normalising to a single value across all snapshots.

src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenValidPlaceOrderCommand_WhenHandling_ThenShouldSendEmail.verified.json (1)

1-1: Remove UTF-8 BOM

Same comment as for the other snapshot files.

src/Services/Finance/BookWorm.Finance.UnitTests/Snapshots/OrderStateMachineTests.GivenOrderTimeout_WhenRetryCountLessThanMax_ThenShouldRetryOrderProcessing_OutputCommand.verified.json (2)

1-1: Strip UTF-8 BOM to minimise diff noise

The snapshot file is saved with a BOM (). Verify’s diff engine sometimes treats this as content, creating unnecessary churn. Saving as plain UTF-8 avoids that headache.


2-4: Switch to IANA-reserved example domain

[email protected] is not an officially reserved test domain and could, in theory, reach a real tenant one day.
Using [email protected] or [email protected] keeps us safely within RFC 2606 guidance.

src/Services/Chat/BookWorm.Chat.UnitTests/Features/Cancel/CancelChatCommandTests.cs (1)

244-252: Avoid double-await for cleaner concurrent test

You await Task.WhenAll(task1, task2) and then immediately await both tasks again when asserting. The second await is redundant because both tasks are already completed.

- await Task.WhenAll(task1, task2);
-
- (await task1).ShouldBe(Unit.Value);
- (await task2).ShouldBe(Unit.Value);
+ var (result1, result2) = await Task.WhenAll(task1, task2) switch
+ {
+     [var r1, var r2] => (r1, r2)
+ };
+
+ result1.ShouldBe(Unit.Value);
+ result2.ShouldBe(Unit.Value);

This keeps the AAA pattern intact and removes unnecessary awaits.

src/Services/Notification/BookWorm.Notification.UnitTests/Snapshots/PlaceOrderConsumerTests.GivenPlaceOrderCommandWithNullEmail_WhenHandling_ThenShouldNotSendEmail.verified.json (1)

2-7: Snapshot structure looks correct – only nit is money precision.

TotalMoney is serialized as 99.99. Across the code-base a decimal is often rendered with 2 or 4 fractional digits (99.9900). If a fixed formatting scrubber is already active this is harmless, otherwise the snapshot may churn when regional settings differ or JsonSerializerOptions change.

src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CleanUpSentEmailConsumerTests.cs (1)

88-89: Good deterministic contract verification!

The contract verification correctly leverages the parameterless nature of CleanUpSentEmailIntegrationEvent for deterministic testing. The explanatory comment adds clarity.

Consider adding contract verification to all test methods for comprehensive coverage:

// Add this pattern to other test methods that don't have it yet
+ // Contract verification - CleanUpSentEmailIntegrationEvent has no parameters so it's deterministic
+ await VerifySnapshot(command);
src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/ResendErrorEmailConsumerTests.cs (1)

151-153: Good contract verification with helpful documentation.

The snapshot verification correctly captures the event contract. The comment explaining that ResendErrorEmailIntegrationEvent is parameterless and deterministic is valuable for maintainability.

Consider moving this verification to match the placement in the first test method (after command creation, before test execution) for consistency across test methods.

src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CancelOrderConsumerTests.cs (1)

73-80: Consider extracting snapshot verification to reduce duplication.

The snapshot verification logic is duplicated across all three test methods with only minor variations in the email property. This violates the DRY principle and increases maintenance overhead.

Extract the common snapshot verification logic into a private helper method:

+    private async Task VerifyContractSnapshot(string? email)
+    {
+        var contractCommand = new CancelOrderCommand(
+            Guid.CreateVersion7(),
+            "John Doe",
+            email,
+            99.99m
+        );
+        await VerifySnapshot(contractCommand);
+    }

     // In each test method, replace the snapshot verification block with:
-        // Contract verification - using deterministic data for snapshot consistency
-        var contractCommand = new CancelOrderCommand(
-            Guid.CreateVersion7(), // OrderId
-            "John Doe", // FullName
-            "[email protected]", // Email
-            99.99m // TotalMoney
-        );
-        await VerifySnapshot(contractCommand);
+        await VerifyContractSnapshot("[email protected]"); // or null, or ""

Also applies to: 113-120, 153-160

src/Services/Notification/BookWorm.Notification.UnitTests/Consumers/CompleteOrderConsumerTests.cs (1)

66-73: Reduce code duplication in snapshot verification.

The same duplication pattern exists here as in CancelOrderConsumerTests. The snapshot verification logic should be extracted to a helper method for better maintainability.

Create a helper method similar to the previous suggestion:

+    private async Task VerifyContractSnapshot(string? email)
+    {
+        var contractCommand = new CompleteOrderCommand(
+            Guid.CreateVersion7(),
+            "John Doe",
+            email,
+            99.99m
+        );
+        await VerifySnapshot(contractCommand);
+    }

Then replace each snapshot verification block with await VerifyContractSnapshot(emailValue);

Also applies to: 106-113, 146-153

src/Services/Catalog/BookWorm.Catalog.UnitTests/Consumers/FeedbackCreatedConsumerTests.cs (1)

66-87: Comprehensive contract verification implementation.

The snapshot verification captures essential contract information including properties, types, and metadata. The structure effectively ensures consumer contract compatibility.

Consider consolidating the Properties and Schema sections if they become repetitive across many tests, potentially through a helper method in SnapshotTestBase.

src/Services/Finance/BookWorm.Finance.UnitTests/OrderStateMachineTests.cs (1)

621-622: Note: Simpler snapshot pattern for timeout events.

The direct object snapshotting is more concise than the comprehensive pattern used elsewhere. While this creates some inconsistency, it may be appropriate for simpler timeout events.

Consider maintaining consistency with the established Input/Output pattern if timeout events require the same level of contract verification detail.

@github-actions

github-actions Bot commented Aug 4, 2025

Copy link
Copy Markdown

Test Results

949 tests  +3   949 ✅ +3   10m 41s ⏱️ +55s
  8 suites ±0     0 💤 ±0 
  8 files   ±0     0 ❌ ±0 

Results for commit 05019ec. ± Comparison against base commit 2397fff.

This pull request removes 3 and adds 6 tests. Note that renamed tests count towards both.
BookWorm.Finance.UnitTests.OrderStateMachineTests ‑ GivenOrderTimeout_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand([email protected], null)
BookWorm.Finance.UnitTests.OrderStateMachineTests ‑ GivenOrderTimeout_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand(null, John Doe)
BookWorm.Finance.UnitTests.OrderStateMachineTests ‑ GivenOrderTimeout_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand(null, null)
BookWorm.Basket.UnitTests.Consumers.PlaceOrderConsumerTests ‑ GivenPlaceOrderCommand_ThenShouldVerifyInputContract
BookWorm.Catalog.UnitTests.Consumers.FeedbackCreatedConsumerTests ‑ GivenFeedbackCreatedIntegrationEvent_ThenShouldVerifyInputContract
BookWorm.Catalog.UnitTests.Consumers.FeedbackDeletedConsumerTests ‑ GivenFeedbackDeletedIntegrationEvent_ThenShouldVerifyInputContract
BookWorm.Finance.UnitTests.OrderStateMachineTests ‑ GivenOrderStatusChangedToCancelEvent_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand([email protected], null)
BookWorm.Finance.UnitTests.OrderStateMachineTests ‑ GivenOrderStatusChangedToCancelEvent_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand(null, John Doe)
BookWorm.Finance.UnitTests.OrderStateMachineTests ‑ GivenOrderStatusChangedToCancelEvent_WhenEmailOrFullNameIsNull_ThenShouldNotPublishCancelOrderCommand(null, null)

♻️ This comment has been updated with latest results.

@foxminchan
foxminchan force-pushed the test/contract-testing branch from 4d2cfb9 to 05019ec Compare August 4, 2025 11:39
@sonarqubecloud

sonarqubecloud Bot commented Aug 4, 2025

Copy link
Copy Markdown

@foxminchan
foxminchan merged commit 56fb2ff into main Aug 4, 2025
17 checks passed
@foxminchan
foxminchan deleted the test/contract-testing branch August 4, 2025 11:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Contract/Snapshot Testing using Verify

2 participants