Skip to content

feat!: omit constructor parameters overloads for interfaces and types with only parameterless constructors - #671

Merged
vbreuss merged 1 commit into
mainfrom
topic/omit-constructorparameters-for-interfaces
Apr 22, 2026
Merged

feat!: omit constructor parameters overloads for interfaces and types with only parameterless constructors#671
vbreuss merged 1 commit into
mainfrom
topic/omit-constructorparameters-for-interfaces

Conversation

@vbreuss

@vbreussvbreuss commented Apr 22, 2026

Copy link
Copy Markdown
Member

This PR updates the Mockolate source generator to stop emitting public CreateMock(... constructorParameters ...) overloads for interfaces and for classes that only have a parameterless constructor, reducing the generated API surface for types that don’t need constructor forwarding.

Changes:

  • Add generator tests asserting that constructor-parameters overloads are omitted for parameterless-only and implicit-ctor classes.
  • Update mock class source generation to only emit constructor-parameter overloads when a type has at least one accessible parameterized constructor.
  • Make the internal “core” CreateMock(MockBehavior?, setup?, object?[]?) helper private for types without parameterized constructors.

@vbreussvbreuss self-assigned this Apr 22, 2026
CopilotAI review requested due to automatic review settings April 22, 2026 12:19
@vbreuss
vbreussforce-pushed the topic/omit-constructorparameters-for-interfaces branch from 18b7b25 to fa6f0fcCompareApril 22, 2026 12:23
@vbreussvbreuss changed the title feat: omit constructor parameters overloads for interfaces and types with only parameterless constructorsfeat!: omit constructor parameters overloads for interfaces and types with only parameterless constructorsApr 22, 2026
@vbreussvbreuss added breaking change The changes require a new major version enhancement New feature or request labels Apr 22, 2026

CopilotAI 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

This PR updates the Mockolate source generator to stop emitting public CreateMock(... constructorParameters ...) overloads for interfaces and for classes that only have a parameterless constructor, reducing the generated API surface for types that don’t need constructor forwarding.

Changes:

  • Add generator tests asserting that constructor-parameters overloads are omitted for parameterless-only and implicit-ctor classes.
  • Update mock class source generation to only emit constructor-parameter overloads when a type has at least one accessible parameterized constructor.
  • Make the internal “core” CreateMock(MockBehavior?, setup?, object?[]?) helper private for types without parameterized constructors.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
Tests/Mockolate.SourceGenerators.Tests/MockTests.csAdds coverage for omitting constructor-parameter overloads on parameterless-only classes.
Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.csGates constructor-parameter overload generation based on presence of accessible parameterized constructors; adjusts helper visibility accordingly.
Comments suppressed due to low confidence (1)

Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs:130

  • By omitting the public CreateMock(..., object?[] ...) overloads for parameterless-only classes, calls like MyType.CreateMock(new object?[]{ }) can now bind to the generic fallback overload emitted in Mock.g.cs (extension<T>(T _)), which compiles but always throws at runtime. To avoid this regression, consider also preventing the fallback overload from being applicable (e.g., remove the fallback constructor-parameters overloads altogether) or emit a type-specific overload that fails at compile time (such as [Obsolete(..., error: true)]) for types where constructor parameters are not supported.
 }
createMockRemarks.Add("</list>");
createMockRemarks.Add("With the default behavior, un-configured members return <c>default</c> values (empty collections / strings, completed tasks, <see langword=\"null\" /> otherwise) and base-class implementations are invoked for class mocks. Use one of the overloads that accepts a <see cref=\"global::Mockolate.MockBehavior\" /> to customize this (for example to make un-configured calls throw or to skip the base class).");
createMockRemarks.Add("Overloads allow you to additionally pass constructor parameters (for class mocks), apply an initial <c>setup</c> callback before the instance is returned, or combine both.");
sb.AppendXmlSummary(
$"Creates a new mock of <see cref=\"{escapedClassName}\" /> with the default <see cref=\"global::Mockolate.MockBehavior\" />.");
sb.AppendXmlRemarks(createMockRemarks.ToArray());

Comment threadTests/Mockolate.SourceGenerators.Tests/MockTests.cs
@github-actions

github-actionsBot commented Apr 22, 2026

Copy link
Copy Markdown

🚀 Benchmark Results

Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.203
[Host] : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v3

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

MethodMeanErrorStdDevRatioRatioSDGen0Gen1AllocatedAlloc Ratio
Event_Mockolate422.1 ns8.25 ns7.72 ns1.000.020.0849-1.39 KB1.00
Event_Moq16,183.9 ns288.34 ns255.60 ns38.350.890.7324-12.51 KB9.00
Event_NSubstitute5,487.3 ns65.07 ns60.87 ns13.000.270.54930.00769.05 KB6.51
Event_FakeItEasy211,459.9 ns1,563.23 ns1,462.24 ns501.109.420.73240.488315.39 KB11.06
Event_Imposter1,432.6 ns51.00 ns47.71 ns3.390.120.53790.01538.8 KB6.33
Event_TUnitMocks183.6 ns4.21 ns3.73 ns0.440.010.08370.00021.37 KB0.98
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Intel Xeon Platinum 8370C CPU 2.80GHz (Max: 2.88GHz), 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.203
[Host] : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v4

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

MethodNMeanErrorStdDevRatioRatioSDGen0Gen1AllocatedAlloc Ratio
Indexer_Mockolate1828.8 ns9.60 ns8.98 ns1.000.010.0944-2.32 KB1.00
Indexer_Moq1138,199.8 ns693.70 ns579.27 ns166.771.880.48830.244114.57 KB6.28
Indexer_NSubstitute16,210.8 ns14.75 ns13.80 ns7.490.080.3815-9.39 KB4.05
Indexer_FakeItEasy16,295.6 ns59.11 ns52.40 ns7.600.100.32810.01538.1 KB3.49
Indexer_Imposter1944.3 ns31.70 ns29.65 ns1.140.040.19650.00194.84 KB2.09
Indexer_Mockolate103,067.1 ns10.82 ns10.12 ns1.000.000.1526-3.83 KB1.00
Indexer_Moq10144,370.7 ns806.18 ns714.66 ns47.070.270.73240.488318.47 KB4.83
Indexer_NSubstitute108,793.4 ns51.09 ns47.79 ns2.870.020.4730-11.85 KB3.10
Indexer_FakeItEasy109,776.8 ns123.62 ns115.63 ns3.190.040.6409-15.81 KB4.13
Indexer_Imposter101,656.4 ns30.47 ns28.51 ns0.540.010.25940.00386.39 KB1.67
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.203
[Host] : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v3

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

MethodNMeanErrorStdDevRatioRatioSDGen0Gen1AllocatedAlloc Ratio
Method_Mockolate1628.3 ns6.98 ns6.53 ns1.000.010.1364-2.23 KB1.00
Method_Moq1183,104.7 ns754.08 ns668.48 ns291.483.100.4883-14.73 KB6.59
Method_NSubstitute15,820.5 ns43.43 ns38.50 ns9.270.110.55690.00769.12 KB4.08
Method_FakeItEasy16,239.9 ns24.35 ns22.78 ns9.930.110.4959-8.11 KB3.63
Method_Imposter1591.1 ns4.73 ns4.42 ns0.940.010.24700.00294.04 KB1.81
Method_TUnitMocks1689.6 ns13.26 ns12.40 ns1.100.020.17740.00102.9 KB1.30
Method_Mockolate102,258.1 ns24.83 ns23.23 ns1.000.010.3357-5.5 KB1.00
Method_Moq10187,682.8 ns1,230.79 ns1,151.29 ns83.120.960.97660.732418.64 KB3.39
Method_NSubstitute108,711.0 ns48.90 ns45.74 ns3.860.040.73240.015312.07 KB2.19
Method_FakeItEasy109,576.0 ns57.83 ns54.09 ns4.240.050.97660.030516.05 KB2.92
Method_Imposter101,237.8 ns13.93 ns13.03 ns0.550.010.33760.00575.52 KB1.00
Method_TUnitMocks101,707.5 ns12.04 ns10.68 ns0.760.010.27470.00194.49 KB0.82
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Intel Xeon Platinum 8370C CPU 2.80GHz (Max: 2.71GHz), 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.203
[Host] : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v4

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

MethodNMeanErrorStdDevRatioRatioSDGen0Gen1AllocatedAlloc Ratio
Property_Mockolate1539.5 ns28.91 ns27.04 ns1.000.070.0610-1.52 KB1.00
Property_Moq13,907.0 ns41.72 ns32.57 ns7.260.350.2136-5.48 KB3.61
Property_NSubstitute14,863.3 ns116.42 ns108.90 ns9.030.470.3510-8.63 KB5.70
Property_FakeItEasy14,197.1 ns148.72 ns139.11 ns7.800.440.2594-6.4 KB4.23
Property_Imposter1528.3 ns41.40 ns38.73 ns0.980.080.11830.00102.91 KB1.92
Property_TUnitMocks1643.5 ns32.48 ns30.38 ns1.200.080.0820-2.03 KB1.34
Property_Mockolate102,050.9 ns56.65 ns52.99 ns1.000.040.1526-3.8 KB1.00
Property_Moq105,452.9 ns143.45 ns134.19 ns2.660.090.3204-7.96 KB2.10
Property_NSubstitute107,176.7 ns164.00 ns145.39 ns3.500.110.45780.007611.3 KB2.98
Property_FakeItEasy107,353.0 ns224.15 ns198.70 ns3.590.130.5341-13.41 KB3.53
Property_Imposter10909.7 ns47.55 ns44.47 ns0.440.020.14400.00103.55 KB0.93
Property_TUnitMocks101,753.0 ns28.93 ns27.06 ns0.860.020.1202-2.97 KB0.78
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.203
[Host] : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v4

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

MethodMeanErrorStdDevRatioRatioSDGen0Gen1AllocatedAlloc Ratio
Callback_Mockolate498.8 ns3.98 ns3.32 ns1.000.010.0658-1.62 KB1.00
Callback_Moq71,165.7 ns290.56 ns242.63 ns142.671.020.2441-8.88 KB5.49
Callback_NSubstitute4,482.2 ns12.72 ns11.28 ns8.990.060.31280.00767.74 KB4.79
Callback_FakeItEasy4,673.0 ns21.33 ns19.95 ns9.370.070.2747-6.8 KB4.20
Callback_Imposter530.5 ns9.69 ns9.06 ns1.060.020.0963-2.38 KB1.47
Callback_TUnitMocks791.6 ns4.89 ns4.34 ns1.590.010.10680.00102.63 KB1.62

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

Test Results

21 files 21 suites 7m 39s ⏱️
3 285 tests 3 284 ✅ 1 💤 0 ❌
21 504 runs 21 503 ✅ 1 💤 0 ❌

Results for commit fa6f0fc.

@vbreuss
vbreuss merged commit ca3d554 into mainApr 22, 2026
16 checks passed
@vbreuss
vbreuss deleted the topic/omit-constructorparameters-for-interfaces branch April 22, 2026 12:36
@github-actions

Copy link
Copy Markdown

This is addressed in release v3.0.0.

@github-actionsgithub-actionsBot added the state: released The issue is released label Apr 30, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking changeThe changes require a new major versionenhancementNew feature or requeststate: releasedThe issue is released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@vbreuss