Skip to content

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

Merged
vbreuss merged 1 commit intomainfrom
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 intomainfrom
topic/omit-constructorparameters-for-interfaces

Conversation

@vbreuss
Copy link
Copy Markdown
Member

@vbreuss vbreuss commented Apr 22, 2026

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.

@vbreuss vbreuss self-assigned this Apr 22, 2026
Copilot AI review requested due to automatic review settings April 22, 2026 12:19
@vbreuss vbreuss force-pushed the topic/omit-constructorparameters-for-interfaces branch from 18b7b25 to fa6f0fc Compare April 22, 2026 12:23
@vbreuss vbreuss changed the title feat: omit constructor parameters overloads for interfaces and types with only parameterless constructors feat!: omit constructor parameters overloads for interfaces and types with only parameterless constructors Apr 22, 2026
@vbreuss vbreuss added breaking change The changes require a new major version enhancement New feature or request labels Apr 22, 2026
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

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.

File Description
Tests/Mockolate.SourceGenerators.Tests/MockTests.cs Adds coverage for omitting constructor-parameter overloads on parameterless-only classes.
Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs Gates 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 thread Tests/Mockolate.SourceGenerators.Tests/MockTests.cs
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 22, 2026

🚀 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

Method Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
Event_Mockolate 422.1 ns 8.25 ns 7.72 ns 1.00 0.02 0.0849 - 1.39 KB 1.00
Event_Moq 16,183.9 ns 288.34 ns 255.60 ns 38.35 0.89 0.7324 - 12.51 KB 9.00
Event_NSubstitute 5,487.3 ns 65.07 ns 60.87 ns 13.00 0.27 0.5493 0.0076 9.05 KB 6.51
Event_FakeItEasy 211,459.9 ns 1,563.23 ns 1,462.24 ns 501.10 9.42 0.7324 0.4883 15.39 KB 11.06
Event_Imposter 1,432.6 ns 51.00 ns 47.71 ns 3.39 0.12 0.5379 0.0153 8.8 KB 6.33
Event_TUnitMocks 183.6 ns 4.21 ns 3.73 ns 0.44 0.01 0.0837 0.0002 1.37 KB 0.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

Method N Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
Indexer_Mockolate 1 828.8 ns 9.60 ns 8.98 ns 1.00 0.01 0.0944 - 2.32 KB 1.00
Indexer_Moq 1 138,199.8 ns 693.70 ns 579.27 ns 166.77 1.88 0.4883 0.2441 14.57 KB 6.28
Indexer_NSubstitute 1 6,210.8 ns 14.75 ns 13.80 ns 7.49 0.08 0.3815 - 9.39 KB 4.05
Indexer_FakeItEasy 1 6,295.6 ns 59.11 ns 52.40 ns 7.60 0.10 0.3281 0.0153 8.1 KB 3.49
Indexer_Imposter 1 944.3 ns 31.70 ns 29.65 ns 1.14 0.04 0.1965 0.0019 4.84 KB 2.09
Indexer_Mockolate 10 3,067.1 ns 10.82 ns 10.12 ns 1.00 0.00 0.1526 - 3.83 KB 1.00
Indexer_Moq 10 144,370.7 ns 806.18 ns 714.66 ns 47.07 0.27 0.7324 0.4883 18.47 KB 4.83
Indexer_NSubstitute 10 8,793.4 ns 51.09 ns 47.79 ns 2.87 0.02 0.4730 - 11.85 KB 3.10
Indexer_FakeItEasy 10 9,776.8 ns 123.62 ns 115.63 ns 3.19 0.04 0.6409 - 15.81 KB 4.13
Indexer_Imposter 10 1,656.4 ns 30.47 ns 28.51 ns 0.54 0.01 0.2594 0.0038 6.39 KB 1.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

Method N Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
Method_Mockolate 1 628.3 ns 6.98 ns 6.53 ns 1.00 0.01 0.1364 - 2.23 KB 1.00
Method_Moq 1 183,104.7 ns 754.08 ns 668.48 ns 291.48 3.10 0.4883 - 14.73 KB 6.59
Method_NSubstitute 1 5,820.5 ns 43.43 ns 38.50 ns 9.27 0.11 0.5569 0.0076 9.12 KB 4.08
Method_FakeItEasy 1 6,239.9 ns 24.35 ns 22.78 ns 9.93 0.11 0.4959 - 8.11 KB 3.63
Method_Imposter 1 591.1 ns 4.73 ns 4.42 ns 0.94 0.01 0.2470 0.0029 4.04 KB 1.81
Method_TUnitMocks 1 689.6 ns 13.26 ns 12.40 ns 1.10 0.02 0.1774 0.0010 2.9 KB 1.30
Method_Mockolate 10 2,258.1 ns 24.83 ns 23.23 ns 1.00 0.01 0.3357 - 5.5 KB 1.00
Method_Moq 10 187,682.8 ns 1,230.79 ns 1,151.29 ns 83.12 0.96 0.9766 0.7324 18.64 KB 3.39
Method_NSubstitute 10 8,711.0 ns 48.90 ns 45.74 ns 3.86 0.04 0.7324 0.0153 12.07 KB 2.19
Method_FakeItEasy 10 9,576.0 ns 57.83 ns 54.09 ns 4.24 0.05 0.9766 0.0305 16.05 KB 2.92
Method_Imposter 10 1,237.8 ns 13.93 ns 13.03 ns 0.55 0.01 0.3376 0.0057 5.52 KB 1.00
Method_TUnitMocks 10 1,707.5 ns 12.04 ns 10.68 ns 0.76 0.01 0.2747 0.0019 4.49 KB 0.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

Method N Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
Property_Mockolate 1 539.5 ns 28.91 ns 27.04 ns 1.00 0.07 0.0610 - 1.52 KB 1.00
Property_Moq 1 3,907.0 ns 41.72 ns 32.57 ns 7.26 0.35 0.2136 - 5.48 KB 3.61
Property_NSubstitute 1 4,863.3 ns 116.42 ns 108.90 ns 9.03 0.47 0.3510 - 8.63 KB 5.70
Property_FakeItEasy 1 4,197.1 ns 148.72 ns 139.11 ns 7.80 0.44 0.2594 - 6.4 KB 4.23
Property_Imposter 1 528.3 ns 41.40 ns 38.73 ns 0.98 0.08 0.1183 0.0010 2.91 KB 1.92
Property_TUnitMocks 1 643.5 ns 32.48 ns 30.38 ns 1.20 0.08 0.0820 - 2.03 KB 1.34
Property_Mockolate 10 2,050.9 ns 56.65 ns 52.99 ns 1.00 0.04 0.1526 - 3.8 KB 1.00
Property_Moq 10 5,452.9 ns 143.45 ns 134.19 ns 2.66 0.09 0.3204 - 7.96 KB 2.10
Property_NSubstitute 10 7,176.7 ns 164.00 ns 145.39 ns 3.50 0.11 0.4578 0.0076 11.3 KB 2.98
Property_FakeItEasy 10 7,353.0 ns 224.15 ns 198.70 ns 3.59 0.13 0.5341 - 13.41 KB 3.53
Property_Imposter 10 909.7 ns 47.55 ns 44.47 ns 0.44 0.02 0.1440 0.0010 3.55 KB 0.93
Property_TUnitMocks 10 1,753.0 ns 28.93 ns 27.06 ns 0.86 0.02 0.1202 - 2.97 KB 0.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

Method Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
Callback_Mockolate 498.8 ns 3.98 ns 3.32 ns 1.00 0.01 0.0658 - 1.62 KB 1.00
Callback_Moq 71,165.7 ns 290.56 ns 242.63 ns 142.67 1.02 0.2441 - 8.88 KB 5.49
Callback_NSubstitute 4,482.2 ns 12.72 ns 11.28 ns 8.99 0.06 0.3128 0.0076 7.74 KB 4.79
Callback_FakeItEasy 4,673.0 ns 21.33 ns 19.95 ns 9.37 0.07 0.2747 - 6.8 KB 4.20
Callback_Imposter 530.5 ns 9.69 ns 9.06 ns 1.06 0.02 0.0963 - 2.38 KB 1.47
Callback_TUnitMocks 791.6 ns 4.89 ns 4.34 ns 1.59 0.01 0.1068 0.0010 2.63 KB 1.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 main Apr 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-actions github-actions Bot added the state: released The issue is released label Apr 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change The changes require a new major version enhancement New feature or request state: released The issue is released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants