feat: allow verifying method setup calls#493
Conversation
There was a problem hiding this comment.
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 throughMockRegistration.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. |
🚀 Benchmark ResultsDetails
|
|
| => methodInvocation.Name.Equals(methodName) && | ||
| methodInvocation.Parameters.Length == parameters.Length && | ||
| !parameters | ||
| .Where((parameter, i) => !parameter.Matches(methodInvocation.Parameters[i])) | ||
| .Any(); | ||
|
|
There was a problem hiding this comment.
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.
| => 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; | |
| } |
| /// <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( |
There was a problem hiding this comment.
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.
| /// <inheritdoc cref="IVerifiableMethodSetup.GetMatch()" /> | ||
| public IMethodMatch GetMatch() | ||
| => methodMatch; |
There was a problem hiding this comment.
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).
|
This is addressed in release v1.5.0. |



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:
IMethodMatch+ match implementations (MethodParameterMatch,MethodParametersMatch) and threads them throughMockRegistration.Method(...).MockExtensions.InvokedSetup(...)to verify invocations for a given setup.