diff --git a/Buildenator.Abstraction/BuildenatorConfigurationAttribute.cs b/Buildenator.Abstraction/BuildenatorConfigurationAttribute.cs
index 4504bbf..8fc1984 100644
--- a/Buildenator.Abstraction/BuildenatorConfigurationAttribute.cs
+++ b/Buildenator.Abstraction/BuildenatorConfigurationAttribute.cs
@@ -17,6 +17,7 @@ public sealed class BuildenatorConfigurationAttribute : Attribute
/// If you want to generate static property that will return a new builder instance.
/// If true, collection fields will be initialized with empty collections in the constructor instead of null.
/// If true, generates additional With methods that accept Func<ChildBuilder, ChildBuilder> for properties that have their own builders.
+ /// If true, all generated builders in this assembly will require the entity's constructor parameters as mandatory builder constructor arguments. Incompatible with mocking.
public BuildenatorConfigurationAttribute(
string buildingMethodsPrefix = "With",
bool generateDefaultBuildMethod = true,
@@ -25,7 +26,8 @@ public BuildenatorConfigurationAttribute(
bool implicitCast = false,
bool generateStaticPropertyForBuilderCreation = false,
bool initializeCollectionsWithEmpty = true,
- bool useChildBuilders = true)
+ bool useChildBuilders = true,
+ bool builderConstructorMandatoryParameters = false)
{
}
}
\ No newline at end of file
diff --git a/Buildenator.Abstraction/MakeBuilderAttribute.cs b/Buildenator.Abstraction/MakeBuilderAttribute.cs
index a01e3fd..0a0ab31 100644
--- a/Buildenator.Abstraction/MakeBuilderAttribute.cs
+++ b/Buildenator.Abstraction/MakeBuilderAttribute.cs
@@ -19,6 +19,7 @@ public sealed class MakeBuilderAttribute : Attribute
/// If you want to generate static property that will return a new builder instance.
/// If true, collection fields will be initialized with empty collections in the constructor instead of null.
/// If true, generates additional With methods that accept Func<ChildBuilder, ChildBuilder> for properties that have their own builders.
+ /// If true, the generated builder constructor will require the entity's constructor parameters as mandatory arguments instead of using a parameterless constructor. Incompatible with mocking.
public MakeBuilderAttribute(
Type typeForBuilder,
string? buildingMethodsPrefix = "With",
@@ -29,7 +30,8 @@ public MakeBuilderAttribute(
string? staticFactoryMethodName = null,
object? generateStaticPropertyForBuilderCreation = null,
object? initializeCollectionsWithEmpty = null,
- object? useChildBuilders = null
+ object? useChildBuilders = null,
+ object? builderConstructorMandatoryParameters = null
)
{
}
diff --git a/Buildenator/AnalyzerReleases.Unshipped.md b/Buildenator/AnalyzerReleases.Unshipped.md
index 2e0db60..03696d6 100644
--- a/Buildenator/AnalyzerReleases.Unshipped.md
+++ b/Buildenator/AnalyzerReleases.Unshipped.md
@@ -9,4 +9,6 @@ BDN002 | Buildenator | Error | BuildersGenerator
BDN003 | Buildenator | Info | BuildenatorDiagnosticDescriptors
BDN004 | Buildenator | Info | BuildenatorDiagnosticDescriptors
BDN005 | Buildenator | Info | BuildenatorDiagnosticDescriptors
-BDN006 | Buildenator | Info | BuildenatorDiagnosticDescriptors
\ No newline at end of file
+BDN006 | Buildenator | Info | BuildenatorDiagnosticDescriptors
+BDN007 | Buildenator | Error | BuildenatorDiagnosticDescriptors
+BDN008 | Buildenator | Error | BuildenatorDiagnosticDescriptors
\ No newline at end of file
diff --git a/Buildenator/Buildenator.csproj b/Buildenator/Buildenator.csproj
index 40e987d..6bd7832 100644
--- a/Buildenator/Buildenator.csproj
+++ b/Buildenator/Buildenator.csproj
@@ -9,7 +9,7 @@
false
true
- 8.5.0.2
+ 8.8.0.0
diff --git a/Buildenator/Configuration/BuilderProperties.cs b/Buildenator/Configuration/BuilderProperties.cs
index 6ff659d..82fc18f 100644
--- a/Buildenator/Configuration/BuilderProperties.cs
+++ b/Buildenator/Configuration/BuilderProperties.cs
@@ -31,6 +31,7 @@ public static BuilderProperties Create(
bool? generateStaticPropertyForBuilderCreation = null;
bool? initializeCollectionsWithEmpty = null;
bool? useChildBuilders = null;
+ bool? builderConstructorMandatoryParameters = null;
if (globalAttributes.HasValue)
{
@@ -42,6 +43,7 @@ public static BuilderProperties Create(
generateStaticPropertyForBuilderCreation = globalAttributes.Value.GetOrThrow(5, nameof(MakeBuilderAttributeInternal.GenerateStaticPropertyForBuilderCreation));
initializeCollectionsWithEmpty = globalAttributes.Value.GetOrThrow(6, nameof(MakeBuilderAttributeInternal.InitializeCollectionsWithEmpty));
useChildBuilders = globalAttributes.Value.GetOrThrow(7, nameof(MakeBuilderAttributeInternal.UseChildBuilders));
+ builderConstructorMandatoryParameters = globalAttributes.Value.GetOrThrow(8, nameof(MakeBuilderAttributeInternal.BuilderConstructorMandatoryParameters));
}
nullableStrategy = builderAttribute.NullableStrategy is null ? nullableStrategy: builderAttribute.NullableStrategy;
@@ -64,7 +66,8 @@ public static BuilderProperties Create(
builderAttribute.StaticFactoryMethodName,
builderAttribute.GenerateStaticPropertyForBuilderCreation ?? generateStaticPropertyForBuilderCreation,
builderAttribute.InitializeCollectionsWithEmpty ?? initializeCollectionsWithEmpty,
- builderAttribute.UseChildBuilders ?? useChildBuilders));
+ builderAttribute.UseChildBuilders ?? useChildBuilders,
+ builderAttribute.BuilderConstructorMandatoryParameters ?? builderConstructorMandatoryParameters));
}
private BuilderProperties(INamespaceOrTypeSymbol builderSymbol, MakeBuilderAttributeInternal attributeData)
@@ -82,6 +85,7 @@ private BuilderProperties(INamespaceOrTypeSymbol builderSymbol, MakeBuilderAttri
GenerateStaticPropertyForBuilderCreation = attributeData.GenerateStaticPropertyForBuilderCreation ?? false;
InitializeCollectionsWithEmpty = attributeData.InitializeCollectionsWithEmpty ?? true;
UseChildBuilders = attributeData.UseChildBuilders ?? true;
+ BuilderConstructorMandatoryParameters = attributeData.BuilderConstructorMandatoryParameters ?? false;
if (string.IsNullOrWhiteSpace(BuildingMethodsPrefix))
throw new ArgumentNullException(nameof(attributeData), "Prefix name shouldn't be empty!");
@@ -182,6 +186,7 @@ private static bool IsAccessibleDefaultValueMember(bool isStatic, Accessibility
public bool GenerateStaticPropertyForBuilderCreation { get; }
public bool InitializeCollectionsWithEmpty { get; }
public bool UseChildBuilders { get; }
+ public bool BuilderConstructorMandatoryParameters { get; }
public IReadOnlyDictionary> BuildingMethods => _buildingMethods;
public IReadOnlyDictionary Fields => _fields;
diff --git a/Buildenator/Configuration/Contract/IBuilderProperties.cs b/Buildenator/Configuration/Contract/IBuilderProperties.cs
index 727ae7a..4d1ac35 100644
--- a/Buildenator/Configuration/Contract/IBuilderProperties.cs
+++ b/Buildenator/Configuration/Contract/IBuilderProperties.cs
@@ -27,6 +27,7 @@ internal interface IBuilderProperties
bool GenerateStaticPropertyForBuilderCreation { get; }
bool InitializeCollectionsWithEmpty { get; }
bool UseChildBuilders { get; }
+ bool BuilderConstructorMandatoryParameters { get; }
///
/// Gets the set of user-defined default value names available in this builder.
diff --git a/Buildenator/Diagnostics/BuildenatorDiagnosticDescriptors.cs b/Buildenator/Diagnostics/BuildenatorDiagnosticDescriptors.cs
index 8abb374..c74c1da 100644
--- a/Buildenator/Diagnostics/BuildenatorDiagnosticDescriptors.cs
+++ b/Buildenator/Diagnostics/BuildenatorDiagnosticDescriptors.cs
@@ -52,4 +52,20 @@ internal static class BuildenatorDiagnosticDescriptors
"Buildenator",
DiagnosticSeverity.Info,
true);
+
+ internal static readonly DiagnosticDescriptor MandatoryParametersWithMockingDiagnostic = new(
+ "BDN007",
+ "BuilderConstructorMandatoryParameters is incompatible with mocking",
+ "The builder '{0}' has BuilderConstructorMandatoryParameters = true, which is incompatible with a mocking configuration. Remove the mocking configuration or disable BuilderConstructorMandatoryParameters.",
+ "Buildenator",
+ DiagnosticSeverity.Error,
+ true);
+
+ internal static readonly DiagnosticDescriptor MandatoryParametersWithFixtureDiagnostic = new(
+ "BDN008",
+ "BuilderConstructorMandatoryParameters is incompatible with fixture configuration",
+ "The builder '{0}' has BuilderConstructorMandatoryParameters = true, which is incompatible with a fixture configuration. Remove the fixture configuration or disable BuilderConstructorMandatoryParameters.",
+ "Buildenator",
+ DiagnosticSeverity.Error,
+ true);
}
\ No newline at end of file
diff --git a/Buildenator/Generators/BuilderSourceStringGenerator.cs b/Buildenator/Generators/BuilderSourceStringGenerator.cs
index 740a6be..2f6b456 100644
--- a/Buildenator/Generators/BuilderSourceStringGenerator.cs
+++ b/Buildenator/Generators/BuilderSourceStringGenerator.cs
@@ -34,6 +34,20 @@ public BuilderSourceStringGenerator(
{
_diagnostics.Add(privateConstructorDiagnostic);
}
+ if (_builder.BuilderConstructorMandatoryParameters && mockingConfiguration != null)
+ {
+ _diagnostics.Add(new BuildenatorDiagnostic(
+ BuildenatorDiagnosticDescriptors.MandatoryParametersWithMockingDiagnostic,
+ _builder.OriginalLocation,
+ _builder.Name));
+ }
+ if (_builder.BuilderConstructorMandatoryParameters && fixtureConfiguration != null)
+ {
+ _diagnostics.Add(new BuildenatorDiagnostic(
+ BuildenatorDiagnosticDescriptors.MandatoryParametersWithFixtureDiagnostic,
+ _builder.OriginalLocation,
+ _builder.Name));
+ }
_diagnostics.AddRange(_builder.Diagnostics);
_diagnostics.AddRange(_entity.Diagnostics);
@@ -67,11 +81,11 @@ namespace {_builder.ContainingNamespace}
{GenerateGlobalNullable()}{GenerateBuilderDefinition()}
{{
{(_fixtureConfiguration is null ? string.Empty : $" private readonly {_fixtureConfiguration.Name} {DefaultConstants.FixtureLiteral} = new {_fixtureConfiguration.Name}({_fixtureConfiguration.ConstructorParameters});")}
-{(_builder.IsDefaultConstructorOverriden ? string.Empty : GenerateConstructor(_builder.Name, _entity, _fixtureConfiguration, _builder.InitializeCollectionsWithEmpty))}
+{(_builder.IsDefaultConstructorOverriden ? string.Empty : GenerateConstructor(_builder.Name, _entity, _fixtureConfiguration, _builder.InitializeCollectionsWithEmpty, _builder.BuilderConstructorMandatoryParameters))}
{_propertiesStringGenerator.GeneratePropertiesCode()}
{(_builder.IsBuildMethodOverriden ? string.Empty : _entity.GenerateBuildsCode(_builder.ShouldGenerateMethodsForUnreachableProperties))}
{(_builder.IsBuildManyMethodOverriden ? string.Empty : GenerateBuildManyCode())}
-{(_builder.GenerateStaticPropertyForBuilderCreation ? $" public static {_builder.FullName} {_entity.Name} => new {_builder.FullName}();" : "")}
+{(_builder.GenerateStaticPropertyForBuilderCreation && !_builder.BuilderConstructorMandatoryParameters ? $" public static {_builder.FullName} {_entity.Name} => new {_builder.FullName}();" : "")}
{(_builder.GenerateDefaultBuildMethod ? _entity.GenerateDefaultBuildsCode() : string.Empty)}
{(_builder.ImplicitCast ? GenerateImplicitCastCode() : string.Empty)}
{GeneratePreBuildMethod()}
diff --git a/Buildenator/Generators/ConstructorsGenerator.cs b/Buildenator/Generators/ConstructorsGenerator.cs
index 19c7dc5..611f502 100644
--- a/Buildenator/Generators/ConstructorsGenerator.cs
+++ b/Buildenator/Generators/ConstructorsGenerator.cs
@@ -9,6 +9,60 @@ namespace Buildenator.Generators;
internal static class ConstructorsGenerator
{
internal static string GenerateConstructor(
+ string builderName,
+ IEntityToBuild entity,
+ IFixtureProperties? fixtureConfiguration,
+ bool initializeCollectionsWithEmpty,
+ bool builderConstructorMandatoryParameters)
+ {
+ return builderConstructorMandatoryParameters
+ ? GenerateMandatoryParamConstructor(builderName, entity, initializeCollectionsWithEmpty)
+ : GenerateParameterlessConstructor(builderName, entity, fixtureConfiguration, initializeCollectionsWithEmpty);
+ }
+
+ private static string GenerateMandatoryParamConstructor(
+ string builderName,
+ IEntityToBuild entity,
+ bool initializeCollectionsWithEmpty)
+ {
+ var constructorToBuild = entity.ConstructorToBuild;
+ var mandatoryParams = constructorToBuild?.Parameters.ToList() ?? [];
+
+ var signatureParams = string.Join(", ", mandatoryParams.Select(p => $"{p.TypeFullName} {p.SymbolName}"));
+
+ var output = new StringBuilder();
+ output.AppendLine($@"{CommentsGenerator.GenerateSummaryOverrideComment()}
+ public {builderName}({signatureParams})
+ {{");
+
+ foreach (var p in mandatoryParams)
+ {
+ output.AppendLine($@" {p.UnderScoreName} = new {DefaultConstants.NullBox}<{p.TypeFullName}>({p.SymbolName});");
+ }
+
+ var settableProperties = entity.AllUniqueSettablePropertiesAndParameters
+ .Where(p => constructorToBuild?.ContainsParameter(p.SymbolPascalName) != true)
+ .ToList();
+
+ if (initializeCollectionsWithEmpty)
+ {
+ foreach (var typedSymbol in settableProperties.Where(ShouldInitializeCollectionField))
+ {
+ var collectionMetadata = typedSymbol.GetCollectionMetadata();
+ if (collectionMetadata != null)
+ {
+ var initCode = GenerateEmptyCollectionInitialization(typedSymbol, collectionMetadata);
+ if (!string.IsNullOrEmpty(initCode))
+ output.AppendLine($@" {initCode}");
+ }
+ }
+ }
+
+ output.AppendLine($@" }}");
+ return output.ToString();
+ }
+
+ private static string GenerateParameterlessConstructor(
string builderName,
IEntityToBuild entity,
IFixtureProperties? fixtureConfiguration,
diff --git a/Buildenator/MakeBuilderAttributeInternal.cs b/Buildenator/MakeBuilderAttributeInternal.cs
index 5622a80..39900c3 100644
--- a/Buildenator/MakeBuilderAttributeInternal.cs
+++ b/Buildenator/MakeBuilderAttributeInternal.cs
@@ -13,7 +13,8 @@ internal readonly struct MakeBuilderAttributeInternal(
string? staticFactoryMethodName,
bool? generateStaticPropertyForBuilderCreation,
bool? initializeCollectionsWithEmpty,
- bool? useChildBuilders)
+ bool? useChildBuilders,
+ bool? builderConstructorMandatoryParameters)
{
public MakeBuilderAttributeInternal(AttributeData attribute)
@@ -29,7 +30,8 @@ attribute.ConstructorArguments[3].Value is null
(string?)attribute.ConstructorArguments[6].Value,
(bool?)attribute.ConstructorArguments[7].Value,
(bool?)attribute.ConstructorArguments[8].Value,
- (bool?)attribute.ConstructorArguments[9].Value)
+ (bool?)attribute.ConstructorArguments[9].Value,
+ (bool?)attribute.ConstructorArguments[10].Value)
{
}
@@ -43,5 +45,6 @@ attribute.ConstructorArguments[3].Value is null
public bool? GenerateStaticPropertyForBuilderCreation { get; } = generateStaticPropertyForBuilderCreation;
public bool? InitializeCollectionsWithEmpty { get; } = initializeCollectionsWithEmpty;
public bool? UseChildBuilders { get; } = useChildBuilders;
+ public bool? BuilderConstructorMandatoryParameters { get; } = builderConstructorMandatoryParameters;
internal string? StaticFactoryMethodName { get; } = staticFactoryMethodName;
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e825538..5469e8c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,39 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## 8.8.0.0 - 2026-3-6
+
+### Added
+- **`builderConstructorMandatoryParameters` option**: New configuration option that makes the generated builder enforce mandatory parameters by requiring the entity's constructor parameters as arguments to the builder's own constructor.
+ - Enabled per builder: `[MakeBuilder(typeof(MyClass), builderConstructorMandatoryParameters: true)]`
+ - Enabled globally: `[assembly: BuildenatorConfiguration(builderConstructorMandatoryParameters: true)]`
+ - When enabled:
+ - The builder gets a **parameterized constructor** mirroring the entity's primary constructor instead of a parameterless one.
+ - The **static factory property** (`generateStaticPropertyForBuilderCreation`) is automatically suppressed, since it would call a parameterless constructor that no longer exists.
+ - All `With...` methods remain available and can still override the values passed to the constructor.
+ - **Mocking is incompatible** — combining this option with a mocking configuration (e.g. `MoqConfiguration`) produces a compile-time error **BDN007**.
+ - **Fixture configuration is incompatible** — combining this option with a fixture configuration (e.g. `AutoFixtureConfiguration`) produces a compile-time error **BDN008**.
+ - Example:
+ ```csharp
+ public class Dto
+ {
+ public Dto(int lineNumber, string activity) { LineNumber = lineNumber; Activity = activity; }
+ public int LineNumber { get; set; }
+ public string Activity { get; set; }
+ public List Tags { get; set; } = [];
+ }
+
+ [MakeBuilder(typeof(Dto), builderConstructorMandatoryParameters: true)]
+ public partial class DtoBuilder { }
+
+ // Usage — constructor enforces required values, With methods allow overrides
+ var dto = new DtoBuilder(lineNumber: 1, activity: "shipping")
+ .AddToTags("express")
+ .Build();
+ ```
+- **BDN007 diagnostic error**: Emitted when `builderConstructorMandatoryParameters = true` is combined with a mocking configuration, since the two features are fundamentally incompatible.
+- **BDN008 diagnostic error**: Emitted when `builderConstructorMandatoryParameters = true` is combined with a fixture configuration, since fixture auto-generation of unset values is incompatible with explicit constructor-driven initialization.
+
## 8.7.1.0 - 2025-12-4
### Fixed
diff --git a/README.md b/README.md
index cedc936..e1c68d2 100644
--- a/README.md
+++ b/README.md
@@ -301,7 +301,8 @@ using Buildenator.Abstraction.Moq;
implicitCast: false,
generateStaticPropertyForBuilderCreation: true,
initializeCollectionsWithEmpty: true, // Default: true - collections are initialized with empty instead of null
- useChildBuilders: true // Default: true - generates Func methods
+ useChildBuilders: true, // Default: true - generates Func methods
+ builderConstructorMandatoryParameters: false // Default: false - require entity constructor params in builder constructor
)]
// Optional: AutoFixture configuration
@@ -328,7 +329,8 @@ Override global settings for specific builders:
staticFactoryMethodName: nameof(User.CreateUser), // Use static factory method
generateStaticPropertyForBuilderCreation: true, // Generate static User property
initializeCollectionsWithEmpty: true, // Default: true - Initialize collections with empty instead of null
- useChildBuilders: true // Default: true - Generate Func methods
+ useChildBuilders: true, // Default: true - Generate Func methods
+ builderConstructorMandatoryParameters: false // Default: false - Require entity constructor params in builder constructor
)]
public partial class UserBuilder { }
```
@@ -547,10 +549,69 @@ var parent2 = ParentBuilder.Parent
.Build();
```
+#### `builderConstructorMandatoryParameters` (default: `false`)
+When `true`, the generated builder constructor takes the entity's primary constructor parameters as required arguments instead of using a parameterless constructor. This communicates intent and prevents constructing invalid objects in tests.
+
+- The static factory property is automatically suppressed (it would need a parameterless constructor).
+- All `With...` methods are still generated and can override the values.
+- **Incompatible with mocking** — causes compiler error **BDN007** if combined with a mocking configuration.
+- **Incompatible with fixture configuration** — causes compiler error **BDN008** if combined with an AutoFixture configuration.
+
+See the [Mandatory Constructor Parameters](#mandatory-constructor-parameters) section in Advanced Usage for a full example.
+
---
## Advanced Usage
+### Mandatory Constructor Parameters
+
+Enforce required initialization values through the builder's own constructor by setting `builderConstructorMandatoryParameters: true`. This is especially useful for DTOs or value objects where constructing an instance without specific required values is either invalid or meaningless.
+
+```csharp
+public class Dto
+{
+ public Dto(int lineNumber, string activity)
+ {
+ LineNumber = lineNumber;
+ Activity = activity;
+ }
+
+ public int LineNumber { get; set; }
+ public string Activity { get; set; }
+ public List Tags { get; set; } = [];
+}
+
+[MakeBuilder(typeof(Dto), builderConstructorMandatoryParameters: true)]
+public partial class DtoBuilder { }
+```
+
+The generated builder constructor mirrors the entity constructor:
+
+```csharp
+// Generated:
+// public DtoBuilder(int lineNumber, string activity) { ... }
+
+// Usage — required parameters are enforced at the call site
+var dto = new DtoBuilder(lineNumber: 1, activity: "shipping")
+ .WithLineNumber(99) // With methods still work and override constructor values
+ .AddToTags("express")
+ .Build();
+```
+
+**Behaviour:**
+- The builder gets a **parameterized constructor** matching the entity's primary constructor (the one with the most parameters).
+- All `With...` and `AddTo...` methods are generated as usual and override the constructor values.
+- The **static factory property** (`generateStaticPropertyForBuilderCreation`) is automatically suppressed, since it would require a parameterless constructor that no longer exists.
+- **Mocking is incompatible** — combining this option with a mocking configuration produces compiler error **BDN007**.
+- **Fixture configuration is incompatible** — combining this option with an AutoFixture configuration produces compiler error **BDN008**.
+
+**Global configuration:**
+
+```csharp
+[assembly: BuildenatorConfiguration(builderConstructorMandatoryParameters: true)]
+```
+
+
### Working with Collections
Buildenator provides powerful collection handling with both `With` and `AddTo` methods.
diff --git a/Tests/Buildenator.IntegrationTests.SharedEntities/EntityWithMandatoryConstructorParameters.cs b/Tests/Buildenator.IntegrationTests.SharedEntities/EntityWithMandatoryConstructorParameters.cs
new file mode 100644
index 0000000..a6ec526
--- /dev/null
+++ b/Tests/Buildenator.IntegrationTests.SharedEntities/EntityWithMandatoryConstructorParameters.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace Buildenator.IntegrationTests.SharedEntities;
+
+public class EntityWithMandatoryConstructorParameters
+{
+ public EntityWithMandatoryConstructorParameters(int lineNumber, string activity, List tags)
+ {
+ LineNumber = lineNumber;
+ Activity = activity;
+ Tags = tags;
+ }
+
+ public int LineNumber { get; set; }
+ public string Activity { get; set; }
+ public List Tags { get; set; }
+}
diff --git a/Tests/Buildenator.IntegrationTests.SourceWithoutAssemblyInfo/EntityWithMandatoryConstructorParametersBuilder.cs b/Tests/Buildenator.IntegrationTests.SourceWithoutAssemblyInfo/EntityWithMandatoryConstructorParametersBuilder.cs
new file mode 100644
index 0000000..e0b257b
--- /dev/null
+++ b/Tests/Buildenator.IntegrationTests.SourceWithoutAssemblyInfo/EntityWithMandatoryConstructorParametersBuilder.cs
@@ -0,0 +1,13 @@
+using Buildenator.Abstraction;
+using Buildenator.IntegrationTests.SharedEntities;
+
+namespace Buildenator.IntegrationTests.SourceWithoutAssemblyInfo
+{
+ [MakeBuilder(
+ typeof(EntityWithMandatoryConstructorParameters),
+ builderConstructorMandatoryParameters: true,
+ initializeCollectionsWithEmpty: true)]
+ public partial class EntityWithMandatoryConstructorParametersBuilder
+ {
+ }
+}
diff --git a/Tests/Buildenator.IntegrationTests/Buildenator.IntegrationTests.csproj b/Tests/Buildenator.IntegrationTests/Buildenator.IntegrationTests.csproj
index 9b58edb..801610c 100644
--- a/Tests/Buildenator.IntegrationTests/Buildenator.IntegrationTests.csproj
+++ b/Tests/Buildenator.IntegrationTests/Buildenator.IntegrationTests.csproj
@@ -26,6 +26,7 @@
+
diff --git a/Tests/Buildenator.IntegrationTests/BuildersGeneratorMandatoryParametersTests.cs b/Tests/Buildenator.IntegrationTests/BuildersGeneratorMandatoryParametersTests.cs
new file mode 100644
index 0000000..56a768f
--- /dev/null
+++ b/Tests/Buildenator.IntegrationTests/BuildersGeneratorMandatoryParametersTests.cs
@@ -0,0 +1,54 @@
+using Buildenator.IntegrationTests.SharedEntities;
+using Buildenator.IntegrationTests.SourceWithoutAssemblyInfo;
+using FluentAssertions;
+using Xunit;
+
+namespace Buildenator.IntegrationTests;
+
+public class BuildersGeneratorMandatoryParametersTests
+{
+ [Fact]
+ public void BuildersGenerator_MandatoryParameters_BuilderRequiresConstructorArguments()
+ {
+ var result = new EntityWithMandatoryConstructorParametersBuilder(42, "shipping", ["tag1", "tag2"])
+ .Build();
+
+ result.LineNumber.Should().Be(42);
+ result.Activity.Should().Be("shipping");
+ result.Tags.Should().BeEquivalentTo(["tag1", "tag2"]);
+ }
+
+ [Fact]
+ public void BuildersGenerator_MandatoryParameters_WithMethodsOverrideConstructorValues()
+ {
+ var result = new EntityWithMandatoryConstructorParametersBuilder(1, "initial", null)
+ .WithLineNumber(99)
+ .WithActivity("updated")
+ .Build();
+
+ result.LineNumber.Should().Be(99);
+ result.Activity.Should().Be("updated");
+ }
+
+ [Fact]
+ public void BuildersGenerator_MandatoryParameters_CollectionPropertiesStillWork()
+ {
+ var result = new EntityWithMandatoryConstructorParametersBuilder(1, "test", null)
+ .AddToTags("tag1", "tag2")
+ .Build();
+
+ result.Tags.Should().BeEquivalentTo(new[] { "tag1", "tag2" });
+ }
+
+ [Fact]
+ public void BuildersGenerator_MandatoryParameters_NoStaticFactoryPropertyGenerated()
+ {
+ var builderType = typeof(EntityWithMandatoryConstructorParametersBuilder);
+
+ var staticProperty = builderType.GetProperty(
+ nameof(EntityWithMandatoryConstructorParameters),
+ System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
+
+ staticProperty.Should().BeNull("static factory property is incompatible with mandatory constructor parameters");
+ }
+}