Testing is essential for ensuring your Intent Architect modules work correctly and continue to work as you make changes.
Testing Strategy
A comprehensive testing strategy for modules includes:
Integration Tests Test complete code generation from metadata to output
Unit Tests Test individual templates, decorators, and extensions
Output Verification Verify generated code compiles and meets requirements
Regression Tests Ensure changes don’t break existing functionality
Test Application Structure
The recommended approach is to create Intent Architect test applications:
Tests/
├── YourModule.Tests/
│ ├── Intent.Metadata/ # Designer metadata
│ ├── YourModule.Tests.Application/ # Generated application
│ ├── YourModule.Tests.IntegrationTests/ # Test project
│ ├── YourModule.Tests.sln
│ ├── YourModule.Tests.application.config
│ └── modules.config
Creating a Test Application
Step 1: Create the Intent Application
Create new application
Create a new Intent Architect application specifically for testing your module.
Install your module
Add your module (and its dependencies) to the test application.
Create test metadata
Design metadata in the designers that exercises your module’s features.
Run Software Factory
Generate the code and verify it produces expected output.
Step 2: Add Integration Tests
Create a test project to verify the generated code:
< Project Sdk = "Microsoft.NET.Sdk" >
< PropertyGroup >
< TargetFramework > net8 . 0 </ TargetFramework >
< IsPackable > false </ IsPackable >
< IsTestProject > true </ IsTestProject >
</ PropertyGroup >
< ItemGroup >
< PackageReference Include = "Microsoft.NET.Test.Sdk" Version = "17.8.0" />
< PackageReference Include = "MSTest.TestAdapter" Version = "3.1.1" />
< PackageReference Include = "MSTest.TestFramework" Version = "3.1.1" />
</ ItemGroup >
< ItemGroup >
< ProjectReference Include = ".. \Y ourModule.Tests.Application \Y ourModule.Tests.Application.csproj" />
</ ItemGroup >
</ Project >
Integration Testing Patterns
Testing Generated Code Compiles
The most basic test is ensuring generated code compiles:
using Microsoft . VisualStudio . TestTools . UnitTesting ;
namespace YourModule . Tests . IntegrationTests
{
[ TestClass ]
public class CompilationTests
{
[ TestMethod ]
public void GeneratedCodeCompiles ()
{
// If this test project builds successfully,
// it means all generated code compiles
Assert . IsTrue ( true );
}
}
}
Testing Template Output
Verify specific template outputs exist and are correct:
using Microsoft . VisualStudio . TestTools . UnitTesting ;
using YourModule . Tests . Application . Commands ;
namespace YourModule . Tests . IntegrationTests
{
[ TestClass ]
public class CommandHandlerTests
{
[ TestMethod ]
public void CommandHandlerExists ()
{
// Verify the handler class was generated
var handler = new CreateOrderHandler ();
Assert . IsNotNull ( handler );
}
[ TestMethod ]
public void CommandHandlerImplementsCorrectInterface ()
{
// Verify it implements IRequestHandler
var handler = new CreateOrderHandler ();
Assert . IsInstanceOfType ( handler , typeof ( IRequestHandler < CreateOrderCommand >));
}
[ TestMethod ]
public async Task HandlerExecutesWithoutError ()
{
// Test the handler can be instantiated and called
var handler = new CreateOrderHandler ();
var command = new CreateOrderCommand { /* ... */ };
// This will throw NotImplementedException in scaffolded code,
// but verifies the signature is correct
await Assert . ThrowsExceptionAsync < NotImplementedException >(
() => handler . Handle ( command , CancellationToken . None ));
}
}
}
Testing Dependency Injection Configuration
Verify DI registrations are correct:
DependencyInjectionTests.cs
using Microsoft . Extensions . DependencyInjection ;
using Microsoft . VisualStudio . TestTools . UnitTesting ;
using MediatR ;
namespace YourModule . Tests . IntegrationTests
{
[ TestClass ]
public class DependencyInjectionTests
{
[ TestMethod ]
public void MediatRIsRegistered ()
{
// Arrange
var services = new ServiceCollection ();
// Act
ConfigureServices ( services );
var provider = services . BuildServiceProvider ();
// Assert
var mediator = provider . GetService < IMediator >();
Assert . IsNotNull ( mediator );
}
[ TestMethod ]
public void CommandHandlersAreRegistered ()
{
// Arrange
var services = new ServiceCollection ();
ConfigureServices ( services );
var provider = services . BuildServiceProvider ();
// Act
var handler = provider . GetService < IRequestHandler < CreateOrderCommand >>();
// Assert
Assert . IsNotNull ( handler );
}
private void ConfigureServices ( IServiceCollection services )
{
// Call your generated configuration method
services . AddApplication ( /* ... */ );
}
}
}
Testing Business Logic
Test generated repositories, services, and handlers:
using Microsoft . VisualStudio . TestTools . UnitTesting ;
using YourModule . Tests . Application . Repositories ;
using YourModule . Tests . Domain . Entities ;
namespace YourModule . Tests . IntegrationTests
{
[ TestClass ]
public class RepositoryTests
{
private IOrderRepository _repository ;
[ TestInitialize ]
public void Setup ()
{
// Setup in-memory database or mock
_repository = CreateRepository ();
}
[ TestMethod ]
public async Task CanAddAndRetrieveEntity ()
{
// Arrange
var order = new Order { Id = Guid . NewGuid (), /* ... */ };
// Act
await _repository . AddAsync ( order );
var retrieved = await _repository . GetByIdAsync ( order . Id );
// Assert
Assert . IsNotNull ( retrieved );
Assert . AreEqual ( order . Id , retrieved . Id );
}
private IOrderRepository CreateRepository ()
{
// Create repository with test database context
return new OrderRepository ( CreateDbContext ());
}
}
}
Unit Testing Modules
For more granular testing, create unit tests for individual components:
Testing Templates
using Microsoft . VisualStudio . TestTools . UnitTesting ;
using Intent . Engine ;
using Intent . Modules . YourModule . Templates ;
namespace YourModule . UnitTests
{
[ TestClass ]
public class CommandHandlerTemplateTests
{
[ TestMethod ]
public void GeneratesCorrectClassName ()
{
// Arrange
var model = CreateTestModel ( "CreateOrder" );
var template = new CommandHandlerTemplate (
CreateTestOutputTarget (),
model );
// Act
var output = template . TransformText ();
// Assert
Assert . IsTrue ( output . Contains ( "class CreateOrderHandler" ));
}
[ TestMethod ]
public void ImplementsIRequestHandlerInterface ()
{
// Arrange
var model = CreateTestModel ( "CreateOrder" );
var template = new CommandHandlerTemplate (
CreateTestOutputTarget (),
model );
// Act
var output = template . TransformText ();
// Assert
Assert . IsTrue ( output . Contains ( "IRequestHandler<CreateOrderCommand>" ));
}
[ TestMethod ]
public void IncludesRequiredUsings ()
{
// Arrange
var model = CreateTestModel ( "CreateOrder" );
var template = new CommandHandlerTemplate (
CreateTestOutputTarget (),
model );
// Act
var output = template . TransformText ();
// Assert
Assert . IsTrue ( output . Contains ( "using MediatR;" ));
Assert . IsTrue ( output . Contains ( "using System.Threading;" ));
Assert . IsTrue ( output . Contains ( "using System.Threading.Tasks;" ));
}
private CommandModel CreateTestModel ( string name )
{
// Create mock/test model
return new CommandModel ( /* ... */ );
}
private IOutputTarget CreateTestOutputTarget ()
{
// Create mock output target
return Mock . Of < IOutputTarget >();
}
}
}
Testing Decorators
using Microsoft . VisualStudio . TestTools . UnitTesting ;
using Intent . Modules . YourModule . Decorators ;
namespace YourModule . UnitTests
{
[ TestClass ]
public class LoggingDecoratorTests
{
[ TestMethod ]
public void AddsLoggingStatements ()
{
// Arrange
var template = CreateTestTemplate ();
var decorator = new LoggingCommandHandlerDecorator (
template ,
CreateTestApplication ());
// Act
decorator . BeforeHandleMethod ();
var output = template . TransformText ();
// Assert
Assert . IsTrue ( output . Contains ( "_logger.LogInformation" ));
}
[ TestMethod ]
public void AddsRequiredUsings ()
{
// Arrange
var decorator = new LoggingCommandHandlerDecorator (
CreateTestTemplate (),
CreateTestApplication ());
// Act
var usings = decorator . DeclareUsings (). ToList ();
// Assert
Assert . IsTrue ( usings . Contains ( "Microsoft.Extensions.Logging" ));
}
[ TestMethod ]
public void HasCorrectPriority ()
{
// Arrange
var decorator = new LoggingCommandHandlerDecorator (
CreateTestTemplate (),
CreateTestApplication ());
// Assert
Assert . AreEqual ( 10 , decorator . Priority );
}
}
}
Testing Factory Extensions
FactoryExtensionUnitTests.cs
using Microsoft . VisualStudio . TestTools . UnitTesting ;
using Intent . Modules . YourModule . FactoryExtensions ;
namespace YourModule . UnitTests
{
[ TestClass ]
public class DependencyInjectionExtensionTests
{
[ TestMethod ]
public void RegistersMediatRCorrectly ()
{
// Arrange
var application = CreateTestApplication ();
var extension = new DependencyInjectionFactoryExtension ();
// Simulate event
application . EventDispatcher . Publish ( new ContainerRegistrationRequest
{
Concern = "MediatR" ,
ConcreteType = "typeof(MyBehavior)"
});
// Act
extension . OnAfterTemplateRegistrations ( application );
// Assert
var diTemplate = application . FindTemplateInstance < ICSharpFileBuilderTemplate >(
TemplateRoles . Application . DependencyInjection );
var output = diTemplate . TransformText ();
Assert . IsTrue ( output . Contains ( "services.AddMediatR" ));
Assert . IsTrue ( output . Contains ( "cfg.AddOpenBehavior(typeof(MyBehavior))" ));
}
[ TestMethod ]
public void HandlesEventCorrectly ()
{
// Arrange
var extension = new DependencyInjectionFactoryExtension ();
var application = CreateTestApplication ();
extension . OnBeforeTemplateRegistrations ( application );
var @event = new ContainerRegistrationRequest
{
Concern = "MediatR" ,
ConcreteType = "typeof(MyBehavior)"
};
// Act
application . EventDispatcher . Publish ( @event );
// Assert
Assert . IsTrue ( @event . IsHandled );
}
}
}
For comprehensive testing, use real Intent Architect metadata:
[ TestClass ]
public class MetadataBasedTests
{
private IApplication _application ;
[ TestInitialize ]
public void Setup ()
{
// Load the actual test application configuration
_application = LoadTestApplication ( "YourModule.Tests.application.config" );
}
[ TestMethod ]
public void GeneratesExpectedNumberOfHandlers ()
{
// Arrange
var templates = _application . FindTemplateInstances < CommandHandlerTemplate >();
// Assert - based on your test metadata
Assert . AreEqual ( 5 , templates . Count ());
}
[ TestMethod ]
public void AllTemplatesCanExecute ()
{
// Arrange
var templates = _application . FindTemplateInstances < ITemplate >();
// Act & Assert
foreach ( var template in templates )
{
Assert . IsTrue ( template . CanRunTemplate (),
$"Template { template . Id } cannot run" );
var output = template . RunTemplate ();
Assert . IsNotNull ( output );
}
}
private IApplication LoadTestApplication ( string configPath )
{
// Load actual application configuration
// Implementation depends on Intent SDK
return ApplicationConfigLoader . Load ( configPath );
}
}
Automated Testing in CI/CD
Pre-commit Validation Script
The repository includes a pre-commit validation script:
run-pre-commit-checks.ps1
# Build all modules
dotnet build
# Run all tests
dotnet test
# Verify modules package correctly
foreach ( $module in Get-ChildItem - Path "Modules" - Filter "*.csproj" - Recurse) {
dotnet pack $module .FullName
}
Azure Pipelines Configuration
Example pipeline configuration:
trigger :
branches :
include :
- master
- develop
pool :
vmImage : 'windows-latest'
steps :
- task : UseDotNet@2
inputs :
version : '8.x'
- task : DotNetCoreCLI@2
displayName : 'Restore'
inputs :
command : 'restore'
projects : '**/*.csproj'
- task : DotNetCoreCLI@2
displayName : 'Build'
inputs :
command : 'build'
projects : '**/*.csproj'
arguments : '--configuration Release'
- task : DotNetCoreCLI@2
displayName : 'Test'
inputs :
command : 'test'
projects : 'Tests/**/*.IntegrationTests.csproj'
arguments : '--configuration Release'
- task : DotNetCoreCLI@2
displayName : 'Pack Modules'
inputs :
command : 'pack'
projects : 'Modules/**/*.csproj'
arguments : '--configuration Release'
Test-Driven Development for Modules
Follow TDD when developing modules:
Write failing test
Create a test that describes the desired behavior: [ TestMethod ]
public void CommandHandlerHasValidationBehavior ()
{
var output = template . TransformText ();
Assert . IsTrue ( output . Contains ( "IValidator" ));
}
Implement feature
Update your template/decorator to make the test pass.
Refactor
Clean up the implementation while keeping tests green.
Add integration test
Verify the feature works end-to-end in a test application.
Regression Testing
Maintain regression tests for bug fixes:
[ TestClass ]
public class RegressionTests
{
[ TestMethod ]
[ TestCategory ( "Regression" )]
public void Issue123_HandlerShouldNotDuplicateUsings ()
{
// Arrange
var template = CreateTemplateWithMultipleDecorators ();
// Act
var output = template . TransformText ();
// Assert
var usingCount = CountOccurrences ( output , "using MediatR;" );
Assert . AreEqual ( 1 , usingCount , "Should only have one using MediatR statement" );
}
[ TestMethod ]
[ TestCategory ( "Regression" )]
public void Issue456_NullableReturnTypeSupported ()
{
// Test for specific bug fix
var model = CreateModelWithNullableReturn ();
var template = new CommandHandlerTemplate ( CreateTestOutputTarget (), model );
var output = template . TransformText ();
Assert . IsTrue ( output . Contains ( "Task<string?>" ));
}
}
Test Organization
Organize tests by category:
[ TestClass ]
public class TemplateTests
{
[ TestMethod ]
[ TestCategory ( "Template" )]
[ TestCategory ( "CommandHandler" )]
public void CommandHandlerTest () { }
}
[ TestClass ]
public class DecoratorTests
{
[ TestMethod ]
[ TestCategory ( "Decorator" )]
[ TestCategory ( "Validation" )]
public void ValidationDecoratorTest () { }
}
[ TestClass ]
public class IntegrationTests
{
[ TestMethod ]
[ TestCategory ( "Integration" )]
[ TestCategory ( "Slow" )]
public void EndToEndTest () { }
}
Run specific categories:
dotnet test --filter "TestCategory=Integration"
dotnet test --filter "TestCategory!=Slow"
Best Practices
Every template, decorator, and factory extension should have tests.
Use real test applications
Create Intent Architect test applications with representative metadata.
Verify generated code compiles
The minimum test is ensuring generated code compiles without errors.
Test with optional properties, empty collections, null values, etc.
Maintain regression tests
When fixing bugs, add tests to prevent regression.
Automate test execution in your build pipeline.
Categorize tests to run different suites (unit, integration, slow, etc.).
Common Test Scenarios
Template Output
Correct class names
Proper namespaces
Required using statements
Expected methods and properties
Decorator Behavior
Attributes added correctly
Method bodies modified
Constructor parameters injected
Priority ordering
Factory Extensions
Events handled correctly
Templates modified as expected
Dependencies registered
Configuration applied
Integration
Generated code compiles
DI container configured
Application runs
Business logic works
Test Helpers and Utilities
Create helper classes for common test operations:
public static class TestHelpers
{
public static IOutputTarget CreateTestOutputTarget (
string name = "TestProject" ,
string location = "TestLocation" )
{
var mock = new Mock < IOutputTarget >();
mock . Setup ( x => x . Name ). Returns ( name );
mock . Setup ( x => x . Location ). Returns ( location );
return mock . Object ;
}
public static IApplication CreateTestApplication ()
{
var mock = new Mock < IApplication >();
mock . Setup ( x => x . EventDispatcher ). Returns ( new EventDispatcher ());
return mock . Object ;
}
public static CommandModel CreateCommandModel (
string name ,
string returnType = null )
{
// Create test model
return new CommandModel ( /* ... */ );
}
public static int CountOccurrences ( string text , string pattern )
{
return Regex . Matches ( text , Regex . Escape ( pattern )). Count ;
}
}
Debugging Tests
Tips for debugging failing tests:
var output = template . TransformText ();
Console . WriteLine ( output ); // View actual output
File . WriteAllText ( "debug-output.cs" , output ); // Save to file
Set breakpoints in your template/decorator code and debug the test.
Create minimal test cases that reproduce the problem.
Run the Software Factory on your test application and inspect the output manually.
Example Test Suite
Here’s a complete example from the repository structure:
Tests/AdvancedMappingCrud.Repositories.Tests/
├── AdvancedMappingCrud.Repositories.Tests.Application/
│ ├── Commands/
│ │ └── CreateOrderHandler.cs (generated)
│ ├── Repositories/
│ │ └── OrderRepository.cs (generated)
│ └── DependencyInjection.cs (generated)
├── AdvancedMappingCrud.Repositories.Tests.IntegrationTests/
│ ├── Tests/
│ │ ├── OrderRepositoryTests.cs
│ │ ├── CommandHandlerTests.cs
│ │ └── DependencyInjectionTests.cs
│ └── AdvancedMappingCrud.Repositories.Tests.IntegrationTests.csproj
├── Intent.Metadata/
│ └── (designer metadata)
├── AdvancedMappingCrud.Repositories.Tests.sln
└── modules.config
Next Steps
Creating Modules Package your tested modules for distribution
Template Development Create testable templates
Decorators Build decorator components
Factory Extensions Develop factory extensions
Contributing Tests
When contributing to the Intent.Modules.NET repository:
Add test cases for new features
Update existing tests when changing behavior
Run run-pre-commit-checks.ps1 before committing
Ensure all tests pass in CI/CD pipeline
Add test documentation in PR descriptions
The repository includes 200+ test applications demonstrating best practices for module testing.