Description
Mocking a class that declares a required member fails to compile because the generated factory uses an object initializer that does not set the required member.
Minimal repro
```csharp
public abstract class RequiredShape
{
public required string Name { get; init; }
public abstract int Compute();
}
var mock = RequiredShape.Mock();
```
Error (in generated *_MockImplFactory.g.cs):
```
error CS9035: Required member 'RequiredShape.Name' must be set in the object initializer or attribute constructor.
```
Expected
Mock construction should succeed without the user having to set required members — the mock is a test double, it does not need the compile-time enforcement of required.
Actual
Factory can't be instantiated at all, so the type can't be mocked.
Suggested fix
Emit [System.Diagnostics.CodeAnalysis.SetsRequiredMembers] on the generated mock constructor (the private one inside the factory). This tells the compiler that the constructor itself takes responsibility for the required members, bypassing the initializer requirement.
Instructions for the fixing agent
Work test-first. Before touching the generator:
- Add a dedicated test that reproduces this failure. The entry point already exists: unskip and restore the
T17 block in TUnit.Mocks.Tests/KitchenSinkEdgeCasesTests.cs (both the RequiredShape type and the T17_Required_Property_Does_Not_Block_Mock_Instantiation test) and confirm the build fails with the exact CS9035 above in the current codebase.
- Implement the fix in the generator (see Suggested fix).
- Re-run the test and confirm it passes. The test must cover:
- Mock instantiation succeeds without the user providing a value for the required member.
- The abstract/virtual members on the required-carrying type are mockable via
Returns(...) and verifiable via WasCalled.
- Extend the coverage with at least one extra shape: a class that has multiple required members (including a required reference type and a required value type) so the initializer-skip logic is exercised broadly.
- Run the full
TUnit.Mocks.Tests and TUnit.Mocks.SourceGenerator.Tests suites to confirm no regression.
- The test must stay in the suite so any future regression is caught in CI.
Context
Found while adding KitchenSink edge-case coverage in #5674. Tracked in KitchenSinkEdgeCasesTests.cs as T17 SKIPPED.
Description
Mocking a class that declares a
requiredmember fails to compile because the generated factory uses an object initializer that does not set the required member.Minimal repro
```csharp
public abstract class RequiredShape
{
public required string Name { get; init; }
public abstract int Compute();
}
var mock = RequiredShape.Mock();
```
Error (in generated
*_MockImplFactory.g.cs):```
error CS9035: Required member 'RequiredShape.Name' must be set in the object initializer or attribute constructor.
```
Expected
Mock construction should succeed without the user having to set required members — the mock is a test double, it does not need the compile-time enforcement of
required.Actual
Factory can't be instantiated at all, so the type can't be mocked.
Suggested fix
Emit
[System.Diagnostics.CodeAnalysis.SetsRequiredMembers]on the generated mock constructor (the private one inside the factory). This tells the compiler that the constructor itself takes responsibility for the required members, bypassing the initializer requirement.Instructions for the fixing agent
Work test-first. Before touching the generator:
T17block inTUnit.Mocks.Tests/KitchenSinkEdgeCasesTests.cs(both theRequiredShapetype and theT17_Required_Property_Does_Not_Block_Mock_Instantiationtest) and confirm the build fails with the exact CS9035 above in the current codebase.Returns(...)and verifiable viaWasCalled.TUnit.Mocks.TestsandTUnit.Mocks.SourceGenerator.Testssuites to confirm no regression.Context
Found while adding KitchenSink edge-case coverage in #5674. Tracked in
KitchenSinkEdgeCasesTests.csas T17 SKIPPED.