The Unit Test Generator automatically creates tests that verify your constructors properly validate null arguments. This helps ensure your classes properly guard against null dependencies.
- Automatically generates tests for each nullable constructor parameter
- Supports MSTest, xUnit, NUnit, and TUnit testing frameworks
- Validates that
ArgumentNullExceptionis thrown with the correct parameter name - Provides setup hooks for test customization
To use the Unit Test Generator, decorate your test class with the [ConstructorTests] attribute and specify the target type:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq.AutoMock;
[TestClass]
[ConstructorTests(TargetType = typeof(MyController))]
public partial class MyControllerTests
{
}Important: Your test class must be declared as partial for the generator to work.
Given this class:
public class MyController
{
public MyController(IService service, ILogger<MyController> logger)
{
_service = service ?? throw new ArgumentNullException(nameof(service));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
private readonly IService _service;
private readonly ILogger<MyController> _logger;
}This test class:
[TestClass]
[ConstructorTests(TargetType = typeof(MyController))]
public partial class MyControllerTests
{
}Will automatically generate tests like:
[TestMethod]
public void MyControllerConstructor_WithNullIService_ThrowsArgumentNullException()
{
AutoMocker mocker = new AutoMocker();
AutoMockerTestSetup(mocker, "MyControllerConstructor_WithNullIService_ThrowsArgumentNullException");
MyControllerConstructor_WithNullIService_ThrowsArgumentNullExceptionSetup(mocker);
using(IDisposable mockerDisposable = mocker.AsDisposable())
{
var logger = mocker.Get<ILogger<MyController>>();
ArgumentNullException ex = Assert.Throws<ArgumentNullException>(() => _ = new MyController(null, logger));
Assert.AreEqual("service", ex.ParamName);
}
}
[TestMethod]
public void MyControllerConstructor_WithNullILogger_ThrowsArgumentNullException()
{
// Similar test for logger parameter...
}The generator provides partial methods you can implement to customize test behavior:
Called before every generated test:
[TestClass]
[ConstructorTests(TargetType = typeof(MyController))]
public partial class MyControllerTests
{
partial void AutoMockerTestSetup(AutoMocker mocker, string testName)
{
// Common setup for all tests
mocker.Use<string>("default value");
}
}Called before a specific generated test:
[TestClass]
[ConstructorTests(TargetType = typeof(MyController))]
public partial class MyControllerTests
{
partial void MyControllerConstructor_WithNullIService_ThrowsArgumentNullExceptionSetup(AutoMocker mocker)
{
// Setup specific to this test
mocker.Use<string>("specific value");
}
}By default, the generator creates tests for all reference-type constructor parameters. If your class uses nullable reference types and you want to skip tests for nullable parameters, use the Behavior property:
public class MyService
{
public MyService(
string name, // Test will be generated
string? nickname, // No test generated (nullable)
int? age = null) // No test generated (nullable value type with default)
{
ArgumentNullException.ThrowIfNull(name);
}
}
[TestClass]
[ConstructorTests(typeof(MyService), Behavior = TestGenerationBehavior.IgnoreNullableParameters)]
public partial class MyServiceTests
{
}With TestGenerationBehavior.IgnoreNullableParameters, tests are skipped for parameters that:
- Are nullable reference types (when nullable reference types are enabled)
- Are nullable value types (e.g.,
int?) - Have a default value of
null
If your class has multiple constructors, the generator creates tests for parameters in all constructors:
public class MyController
{
public MyController(IService service)
{
// ...
}
public MyController(IService service1, IService service2)
{
// ...
}
}This will generate tests for all constructor parameter combinations that could be null.
The Unit Test Generator automatically detects your testing framework and generates appropriate code:
| Framework | Detection | Attributes Used |
|---|---|---|
| MSTest | References Microsoft.VisualStudio.TestTools.UnitTesting |
[TestMethod] |
| xUnit | References xunit.core |
[Fact] |
| NUnit | References nunit.framework |
[Test] |
| TUnit | References TUnit.Core |
[Test] (async) |
Error: When using [ConstructorTests], your test class must be declared as partial.
// ❌ Error
[TestClass]
[ConstructorTests(TargetType = typeof(MyClass))]
public class MyClassTests // Missing 'partial' keyword
{
}
// ✅ Correct
[TestClass]
[ConstructorTests(TargetType = typeof(MyClass))]
public partial class MyClassTests
{
}Warning: Your test project must reference the Moq.AutoMock NuGet package to use the source generators.
dotnet add package Moq.AutoMockError: The [ConstructorTests] attribute must specify which type to generate tests for.
// ❌ Error
[TestClass]
[ConstructorTests] // Missing TargetType
public partial class MyClassTests
{
}
// ✅ Correct
[TestClass]
[ConstructorTests(TargetType = typeof(MyClass))]
public partial class MyClassTests
{
}Warning: Multiple test classes targeting the same type may cause confusion.
// ⚠️ Warning: Both classes test the same type
[ConstructorTests(TargetType = typeof(MyClass))]
public partial class MyClassTests1 { }
[ConstructorTests(TargetType = typeof(MyClass))]
public partial class MyClassTests2 { }The Unit Test Generator only runs when you use the [ConstructorTests] attribute. Simply don't use the attribute to avoid generating constructor tests.
- Ensure your project references
Moq.AutoMock - Clean and rebuild your solution
- Check for diagnostic errors in the Error List window
- Verify the test class is declared as
partial
- Verify the
[ConstructorTests]attribute has aTargetTypespecified - Check that the test class is
partial - Ensure the target class has constructors with reference-type parameters
- Review diagnostic warnings/errors in Visual Studio
Use the global setup hook for common configuration:
partial void AutoMockerTestSetup(AutoMocker mocker, string testName)
{
// Configure common dependencies
mocker.Use<IConfiguration>(mockConfiguration);
}Consider one test class per target class for clarity:
// MyService.cs
public class MyService { }
// MyServiceTests.cs
[ConstructorTests(TargetType = typeof(MyService))]
public partial class MyServiceTests { }To see the generated code, check your project's obj folder or enable source generators output:
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)Generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>