Skip to content

Improve extensibility#47

Open
vfofanov wants to merge 6 commits intoserilog-contrib:mainfrom
vfofanov:feature/improve-extensibility
Open

Improve extensibility#47
vfofanov wants to merge 6 commits intoserilog-contrib:mainfrom
vfofanov:feature/improve-extensibility

Conversation

@vfofanov
Copy link
Copy Markdown

Improve extensibility

Summary

This PR refactors the assertions layer so that adding or supporting new assertion frameworks (e.g. FluentAssertions, Shouldly, AwesomeAssertions) is easier and consistent. It also improves the core in-memory sink (naming, nullable, tests) and fills test gaps across the solution.

Changes

Assertion extensibility

  • Abstractions

    • Introduced Serilog.Sinks.InMemory.Assertions.Abstractions with:
      • InMemorySinkAssertionsFactory – creates framework-specific assertions from an InMemorySink (snapshot).
      • IInMemorySinkAssertionsExtension – contract for framework-specific assertion behavior (e.g. Assert(condition, FailMessage, because, becauseArgs)).
      • AssertionFramework and AssertionFrameworks – identify the active framework and version.
      • FailMessage – structured failure message (message + args) used by extensions.
    • Assertion interfaces (InMemorySinkAssertions, LogEventsAssertions, LogEventAssertion, etc.) remain in the main Assertions assembly and are implemented by each framework-specific package.
  • Factory-based resolution

    • InMemorySinkAssertionUtils now discovers and instantiates the correct InMemorySinkAssertionsFactory by:
      • Detecting the loaded assertion framework (FluentAssertions, AwesomeAssertions, Shouldly) and its version.
      • Loading the corresponding adapter assembly (e.g. Serilog.Sinks.InMemory.FluentAssertions8) and creating its factory implementation.
    • Public Should() extension calls the factory to create assertions from a snapshot of the sink, so each framework only implements the factory and assertion types.
  • Framework adapters

    • FluentAssertions 5/6/7/8, Shouldly 4, AwesomeAssertions 8/9 now:
      • Implement a thin InMemorySinkAssertionsFactoryImpl and use shared BaseAssertions / AssertionExtensions where applicable.
      • Delegate failure reporting through IInMemorySinkAssertionsExtension and FailMessage, reducing duplicated failure-construction logic and making it straightforward to add new frameworks or versions.

Test layout and coverage

  • Shared assertion tests

    • Assertion tests live under test/Serilog.Sinks.InMemory.Assertions.Tests.Unit/ and are linked into each framework-specific test project (FluentAssertions5–8, Shouldly4, AwesomeAssertions8/9) so the same scenarios run for every framework.
    • Tests obtain the correct assertions via TestInMemorySinkAssertionExtensions.AssertionsFactory (backed by the same detection as production), so a single test file runs against the currently compiled framework.
  • New and updated tests

    • Core sink (Serilog.Sinks.InMemory.Tests.Unit)
      • GivenNullSinkConfiguration_InMemoryThrowsArgumentNullException – null guard for sinkConfiguration.
      • GivenNullOutputTemplate_InMemoryThrowsArgumentNullException – null guard for outputTemplate.
      • GivenSnapshotIsTaken_SnapshotDoesNotIncludeEventsLoggedAfterSnapshot – snapshot isolation.
      • GivenDisposeIsCalledTwice_DoesNotThrow – double Dispose is safe.
    • Assertions (shared)
      • GivenNoMessages_NotHaveMessageSucceeds and GivenNoMessages_NotHaveMessageWithTemplateSucceedsNotHaveMessage() / NotHaveMessage(template) when no events are logged.
      • New file WhenAssertingWithPredicateHaveMessage(predicate) and NotHaveMessage(predicate) (success and failure cases).

Benefits

  • Easier to add frameworks: New assertion libraries can be supported by adding an adapter project that implements InMemorySinkAssertionsFactory and the assertion interfaces, plus a test project that links the shared tests.
  • Consistent behavior: Shared tests ensure all frameworks behave the same for the same API surface.
  • Clearer structure: Abstractions (factory, extension, fail message) separate “what” from “how” and reduce duplication across framework-specific code.

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.

1 participant