diff --git a/TUnit.Core.SourceGenerator/CodeGenerators/Helpers/InstanceFactoryGenerator.cs b/TUnit.Core.SourceGenerator/CodeGenerators/Helpers/InstanceFactoryGenerator.cs
index 38fb99fadc..1d6e6cc0bb 100644
--- a/TUnit.Core.SourceGenerator/CodeGenerators/Helpers/InstanceFactoryGenerator.cs
+++ b/TUnit.Core.SourceGenerator/CodeGenerators/Helpers/InstanceFactoryGenerator.cs
@@ -6,6 +6,37 @@ namespace TUnit.Core.SourceGenerator.CodeGenerators.Helpers;
public static class InstanceFactoryGenerator
{
+ ///
+ /// Generates code to create an instance of a type with proper required property handling.
+ /// This handles required properties that don't have data sources by initializing them with defaults.
+ ///
+ public static void GenerateInstanceCreation(CodeWriter writer, ITypeSymbol typeSymbol, string variableName)
+ {
+ var className = typeSymbol.GloballyQualified();
+ // Use GetAllRequiredProperties because even properties with data sources need to be
+ // initialized in the object initializer to satisfy C#'s required modifier constraint.
+ // The actual values will be populated by the data sources at runtime.
+ var requiredProperties = RequiredPropertyHelper.GetAllRequiredProperties(typeSymbol).ToArray();
+
+ if (requiredProperties.Length == 0)
+ {
+ writer.AppendLine($"{variableName} = new {className}();");
+ }
+ else
+ {
+ writer.AppendLine($"{variableName} = new {className}()");
+ writer.AppendLine("{");
+ writer.Indent();
+ foreach (var property in requiredProperties)
+ {
+ var defaultValue = RequiredPropertyHelper.GetDefaultValueForType(property.Type);
+ writer.AppendLine($"{property.Name} = {defaultValue},");
+ }
+ writer.Unindent();
+ writer.AppendLine("};");
+ }
+ }
+
public static void GenerateInstanceFactory(CodeWriter writer, ITypeSymbol typeSymbol)
{
GenerateInstanceFactory(writer, typeSymbol, null);
diff --git a/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs b/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs
index 0f232f71d3..8c5f623eb9 100644
--- a/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs
+++ b/TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs
@@ -1048,7 +1048,7 @@ private static void GenerateMethodDataSourceFactory(CodeWriter writer, IMethodSy
writer.AppendLine("else");
writer.AppendLine("{");
writer.Indent();
- writer.AppendLine($"instance = new {fullyQualifiedType}();");
+ InstanceFactoryGenerator.GenerateInstanceCreation(writer, targetType, "instance");
writer.Unindent();
writer.AppendLine("}");
writer.AppendLine($"var result = (({fullyQualifiedType})instance).{methodCall};");
@@ -1080,7 +1080,7 @@ private static void GenerateMethodDataSourceFactory(CodeWriter writer, IMethodSy
writer.AppendLine("else");
writer.AppendLine("{");
writer.Indent();
- writer.AppendLine($"instance = new {fullyQualifiedType}();");
+ InstanceFactoryGenerator.GenerateInstanceCreation(writer, targetType, "instance");
writer.Unindent();
writer.AppendLine("}");
writer.AppendLine($"var result = (({fullyQualifiedType})instance).{methodCall};");
@@ -1124,7 +1124,7 @@ private static void GenerateMethodDataSourceFactory(CodeWriter writer, IMethodSy
writer.AppendLine("else");
writer.AppendLine("{");
writer.Indent();
- writer.AppendLine($"instance = new {fullyQualifiedType}();");
+ InstanceFactoryGenerator.GenerateInstanceCreation(writer, targetType, "instance");
writer.Unindent();
writer.AppendLine("}");
writer.AppendLine($"var result = (({fullyQualifiedType})instance).{methodCall};");
@@ -1167,7 +1167,7 @@ private static void GenerateMethodDataSourceFactory(CodeWriter writer, IMethodSy
writer.AppendLine("else");
writer.AppendLine("{");
writer.Indent();
- writer.AppendLine($"instance = new {fullyQualifiedType}();");
+ InstanceFactoryGenerator.GenerateInstanceCreation(writer, targetType, "instance");
writer.Unindent();
writer.AppendLine("}");
writer.AppendLine($"var result = (({fullyQualifiedType})instance).{methodCall};");
@@ -1217,7 +1217,7 @@ private static void GeneratePropertyDataSourceFactory(CodeWriter writer, IProper
writer.AppendLine("else");
writer.AppendLine("{");
writer.Indent();
- writer.AppendLine($"instance = new {fullyQualifiedType}();");
+ InstanceFactoryGenerator.GenerateInstanceCreation(writer, targetType, "instance");
writer.Unindent();
writer.AppendLine("}");
writer.AppendLine($"var result = (({fullyQualifiedType})instance).{propertyAccess};");
@@ -1249,7 +1249,7 @@ private static void GeneratePropertyDataSourceFactory(CodeWriter writer, IProper
writer.AppendLine("else");
writer.AppendLine("{");
writer.Indent();
- writer.AppendLine($"instance = new {fullyQualifiedType}();");
+ InstanceFactoryGenerator.GenerateInstanceCreation(writer, targetType, "instance");
writer.Unindent();
writer.AppendLine("}");
writer.AppendLine($"var result = (({fullyQualifiedType})instance).{propertyAccess};");
@@ -1293,7 +1293,7 @@ private static void GeneratePropertyDataSourceFactory(CodeWriter writer, IProper
writer.AppendLine("else");
writer.AppendLine("{");
writer.Indent();
- writer.AppendLine($"instance = new {fullyQualifiedType}();");
+ InstanceFactoryGenerator.GenerateInstanceCreation(writer, targetType, "instance");
writer.Unindent();
writer.AppendLine("}");
writer.AppendLine($"var result = (({fullyQualifiedType})instance).{propertyAccess};");
@@ -1336,7 +1336,7 @@ private static void GeneratePropertyDataSourceFactory(CodeWriter writer, IProper
writer.AppendLine("else");
writer.AppendLine("{");
writer.Indent();
- writer.AppendLine($"instance = new {fullyQualifiedType}();");
+ InstanceFactoryGenerator.GenerateInstanceCreation(writer, targetType, "instance");
writer.Unindent();
writer.AppendLine("}");
writer.AppendLine($"var result = (({fullyQualifiedType})instance).{propertyAccess};");
diff --git a/TUnit.TestProject/Bugs/3951/Tests.cs b/TUnit.TestProject/Bugs/3951/Tests.cs
new file mode 100644
index 0000000000..8527375a81
--- /dev/null
+++ b/TUnit.TestProject/Bugs/3951/Tests.cs
@@ -0,0 +1,48 @@
+using TUnit.Core.Interfaces;
+using TUnit.TestProject.Attributes;
+
+namespace TUnit.TestProject.Bugs._3951;
+
+
+public sealed class MyTestGeneratorAttribute : DataSourceGeneratorAttribute where T : MyType, new()
+{
+ protected override IEnumerable> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata) => [() => new T()];
+}
+
+public class MyType;
+
+public class ErrContext: IAsyncInitializer, IAsyncDisposable
+{
+ public ValueTask DisposeAsync() => default;
+ public Task InitializeAsync() => Task.CompletedTask;
+}
+
+public class ErrFixture : IAsyncDisposable, IAsyncInitializer
+{
+ public required ErrContext Fixture { get; set; }
+ public ValueTask DisposeAsync() => default;
+ public Task InitializeAsync() => Task.CompletedTask;
+}
+
+public class ErrTest
+{
+ [ClassDataSource>(Shared = SharedType.PerClass)]
+ public required ErrFixture Fixture { get; init; }
+
+ public IEnumerable> TestExecutions => [() => Fixture.Fixture];
+
+ [MethodDataSource("TestExecutions")]
+
+ [Test]
+ public async Task MyTest(ErrContext context)
+ {
+ await Assert.That(context.GetType()).IsNotAssignableTo();
+ }
+
+ [MyTestGeneratorAttribute]
+ [Test]
+ public async Task MyTest2(MyType t)
+ {
+ await Assert.That(t.GetType()).IsAssignableTo();
+ }
+}