Testing compile-time code
When you build complex aspects, it is a good idea to move the complex compile-time logic, typically some code that queries the code model, to compile-time classes that are not aspects. It is possible to build unit tests for these compile-time classes.
Benefits
The benefit of unit-testing compile-time classes are:
- it is generally simpler to create a complete test coverage with unit tests than with aspect tests (see Testing the Aspects),
- it is easier to debug unit tests than aspect tests.
To create unit tests for your compile-time code
Step 1. Disable pruning of compile-time code
In the project that defines the compile-time code, set the MetalamaRemoveCompileTimeOnlyCode
property to False
:
<Project>
<PropertyGroup>
<MetalamaRemoveCompileTimeOnlyCode>False</MetalamaRemoveCompileTimeOnlyCode>
</PropertyGroup>
</Project>
If you skip this step, calling any compile-time code from a unit test will throw an exception.
Step 2. Create a Xunit test project
Create a Xunit test project as usual.
It is highly recommended that you target .NET 6.0 because temporary files cannot be cleaned up automatically with lower .NET versions.
Step 3. Add the Metalama.Testing.UnitTesting project
<Project>
<ItemGroup>
<PackageReference Include="Metalama.Testing.UnitTesting" Version="CHANGE ME" />
</ItemGroup>
</Project>
Step 4. Create a test class derived from UnitTestClass
Create a new test class and make it derive from UnitTestClass.
public class MyTests : UnitTestClass { }
Step 5. Create test methods
Each test method must call the CreateTestContext() and must dispose of the context at the end of the test method.
Then, typically, your test would call the context.CreateCompilation method to get an ICompilation.
public class MyTests : UnitTestClass
{
[Fact]
public void SimpleTest()
{
// Create a test context and dispose of it at the end of the test.
using var testContext = this.CreateTestContext();
// Create a compilation
var code = @"
class C
{
void M1 () {}
void M2()
{
var x = 0;
x++;
}
}
";
var compilation = testContext.CreateCompilation( code );
var type = compilation.Types.OfName( "C" ).Single();
var m1 = type.Methods.OfName( "M1" ).Single();
// Do any assertion. Typically call your compile-time code here.
Assert.Equal( 0, m1.Parameters.Count );
}
}
Note
Some APIs require the execution context to be set and assigned to your compilation. There is currently no public API to change the execution context.