Skip to content

feat: allow verifying method setup calls#493

Merged
vbreuss merged 3 commits intomainfrom
topic/verify-method-setup
Feb 28, 2026
Merged

feat: allow verifying method setup calls#493
vbreuss merged 3 commits intomainfrom
topic/verify-method-setup

Conversation

@vbreuss
Copy link
Copy Markdown
Contributor

@vbreuss vbreuss commented Feb 28, 2026

Adds a new verification surface that allows asserting how often a specific method setup (not just a method signature) was invoked, by introducing a reusable “method match” abstraction and wiring it through verification.

Key Changes:

  • Introduces IMethodMatch + match implementations (MethodParameterMatch, MethodParametersMatch) and threads them through MockRegistration.Method(...).
  • Adds MockExtensions.InvokedSetup(...) to verify invocations for a given setup.
  • Updates tests (and API snapshots) to cover the new verification behavior and the revised verification plumbing.

@vbreuss vbreuss self-assigned this Feb 28, 2026
@vbreuss vbreuss added the enhancement New feature or request label Feb 28, 2026
Copilot AI review requested due to automatic review settings February 28, 2026 12:50
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new verification surface that allows asserting how often a specific method setup (not just a method signature) was invoked, by introducing a reusable “method match” abstraction and wiring it through verification.

Changes:

  • Introduces IMethodMatch + match implementations (MethodParameterMatch, MethodParametersMatch) and threads them through MockRegistration.Method(...).
  • Adds MockExtensions.InvokedSetup(...) to verify invocations for a given setup.
  • Updates tests (and API snapshots) to cover the new verification behavior and the revised verification plumbing.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
Tests/Mockolate.Tests/MockMethods/VerifyInvokedTests.cs Adds coverage for verifying invocations of a method setup.
Tests/Mockolate.Tests/MockMethods/SetupMethodTests.cs Updates a test helper subclass to satisfy the new MethodSetup ctor requirements.
Tests/Mockolate.Tests/MockMethods/InteractionsTests.cs Refactors interaction verification tests to use MethodParameterMatch.
Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt Updates API snapshot for new/changed public APIs.
Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt Updates API snapshot for new/changed public APIs.
Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt Updates API snapshot for new/changed public APIs.
Source/Mockolate/Setup/VoidMethodSetup.cs Supplies IMethodMatch to the MethodSetup base via new match structs.
Source/Mockolate/Setup/ReturnMethodSetup.cs Supplies IMethodMatch to the MethodSetup base via new match structs.
Source/Mockolate/Setup/MethodSetup.cs Converts MethodSetup to require an IMethodMatch and exposes it via IVerifiableMethodSetup.
Source/Mockolate/Setup/MethodParametersMatch.cs Adds match type for IParameters-based comparisons.
Source/Mockolate/Setup/MethodParameterMatch.cs Adds match type for NamedParameter[]-based comparisons.
Source/Mockolate/Setup/Interfaces.MethodSetup.cs Introduces IMethodSetup/IVerifiableMethodSetup and makes return-setup interfaces extend IMethodSetup.
Source/Mockolate/Setup/IMethodMatch.cs Adds the matching abstraction used by verification.
Source/Mockolate/MockRegistration.Verify.cs Replaces method verification overloads with an IMethodMatch-based overload.
Source/Mockolate/MockExtensions.cs Adds InvokedSetup(...) extension for verifying setup invocations.
Source/Mockolate/Mock.Verify.cs Updates internal verification helpers to use the new match types.
Source/Mockolate.SourceGenerators/Sources/Sources.MethodSetups.cs Updates generated setup classes to call the new MethodSetup base ctor.

Comment thread Tests/Mockolate.Tests/MockMethods/VerifyInvokedTests.cs
Comment thread Source/Mockolate/MockRegistration.Verify.cs
Comment thread Source/Mockolate/Setup/MethodSetup.cs
Comment thread Source/Mockolate/Setup/Interfaces.MethodSetup.cs
Comment thread Source/Mockolate/MockExtensions.cs Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 28, 2026

Test Results

    21 files  ±  0      21 suites  ±0   6m 13s ⏱️ + 1m 2s
 2 755 tests + 26   2 754 ✅ + 26  1 💤 ±0  0 ❌ ±0 
18 502 runs  +182  18 501 ✅ +182  1 💤 ±0  0 ❌ ±0 

Results for commit fc7600a. ± Comparison against base commit 18cd76b.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 28, 2026

🚀 Benchmark Results

Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.3 LTS (Noble Numbat)
AMD EPYC 7763 2.61GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.103
[Host] : .NET 10.0.3 (10.0.3, 10.0.326.7603), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Method Mean Error StdDev Gen0 Gen1 Allocated
Simple_Mockolate 1.623 μs 0.0133 μs 0.0118 μs 0.2460 - 4.04 KB
Simple_Moq 183.571 μs 1.2313 μs 1.1517 μs 0.4883 - 14.55 KB
Simple_NSubstitute 5.878 μs 0.0445 μs 0.0394 μs 0.5569 0.0076 9.14 KB
Simple_FakeItEasy 6.455 μs 0.0494 μs 0.0462 μs 0.4959 - 8.11 KB

Copilot AI review requested due to automatic review settings February 28, 2026 13:29
@sonarqubecloud
Copy link
Copy Markdown

@vbreuss vbreuss merged commit 64405fe into main Feb 28, 2026
16 checks passed
@vbreuss vbreuss deleted the topic/verify-method-setup branch February 28, 2026 13:35
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Comment on lines +20 to +25
=> methodInvocation.Name.Equals(methodName) &&
methodInvocation.Parameters.Length == parameters.Length &&
!parameters
.Where((parameter, i) => !parameter.Matches(methodInvocation.Parameters[i]))
.Any();

Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

MethodParameterMatch.Matches uses LINQ (Where(...).Any()) on each comparison, which adds iterator overhead in a potentially hot verification path. A simple indexed for loop (or All) would avoid the LINQ overhead while keeping the same semantics.

Suggested change
=> methodInvocation.Name.Equals(methodName) &&
methodInvocation.Parameters.Length == parameters.Length &&
!parameters
.Where((parameter, i) => !parameter.Matches(methodInvocation.Parameters[i]))
.Any();
{
if (!methodInvocation.Name.Equals(methodName))
{
return false;
}
if (methodInvocation.Parameters.Length != parameters.Length)
{
return false;
}
for (int index = 0; index < parameters.Length; index++)
{
if (!parameters[index].Matches(methodInvocation.Parameters[index]))
{
return false;
}
}
return true;
}

Copilot uses AI. Check for mistakes.
Comment on lines 14 to 18
/// <summary>
/// Counts the invocations of method <paramref name="methodName" /> with matching <paramref name="parameters" /> on the
/// <paramref name="subject" />.
/// Counts the invocations of methods matching the <paramref name="methodMatch" /> on the <paramref name="subject" />.
/// </summary>
public VerificationResult<T> Method<T>(T subject, string methodName, params NamedParameter[] parameters)
public VerificationResult<T> Method<T>(T subject, IMethodMatch methodMatch)
=> new(
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

MockRegistration.Method<T> is a public API, and (per the API snapshot updates) the overloads that accept (string methodName, params NamedParameter[]) / (string methodName, IParameters) were removed in favor of IMethodMatch. Consider keeping the old overloads (possibly [Obsolete]) and delegating them to the new overload to avoid a breaking change for consumers using MockRegistration directly.

Copilot uses AI. Check for mistakes.
Comment on lines +51 to +53
/// <inheritdoc cref="IVerifiableMethodSetup.GetMatch()" />
public IMethodMatch GetMatch()
=> methodMatch;
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

MethodParameterMatch/MethodParametersMatch are readonly structs but they’re typically passed/stored as IMethodMatch (e.g., MethodSetup(IMethodMatch methodMatch) / GetMatch()), which forces boxing allocations for each instance. If reducing allocations is a goal, consider making the match types sealed classes (or otherwise avoiding interface boxing).

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

This is addressed in release v1.5.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request state: released The issue is released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use setup to verify invocations of this setup

2 participants