Repository navigation
[Bug]: TUnit.Mocks emits trim/AOT warnings on Native AOT publish #7027
Description
Bug report checklist
- I've searched existing issues to ensure this isn't a duplicate
- I've read the documentation and this isn't expected behavior
- I'm using the latest version of TUnit
Description
When publishing a test project that uses TUnit.Mocks with PublishAot=true, ILC reports warnings coming from TUnit.Mocks, even if no custom IDefaultValueProvider or generic mock is used. The tests pass as a native executable, but with TreatWarningsAsErrors the publish fails.
As far as I can tell, MockEngine.HandleCallWithReturn and MockRegistry.CreateClosedGenericMock suppress the warnings with #pragma warning disable, which only affects the Roslyn analyzer, not ILC. Using [UnconditionalSuppressMessage] instead (and [RequiresUnreferencedCode]/[RequiresDynamicCode] on the APIs that set a default value provider) should fix it.
Mocking a generic interface additionally causes IL2069, because OpenGenericFactoryDescriptor only annotates its members with [property: DynamicallyAccessedMembers(...)]. The constructor parameters also need [param: ...].
Expected Behavior
No trim/AOT warnings when using basic mocks (Mock.Of<T>(), Returns, WasCalled).
Actual Behavior
IL2026, IL2055 and 2× IL3050 for a basic mock; 2× IL2069 more for a generic interface mock.
Steps to Reproduce
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TUnit" Version="1.73.19" />
<PackageReference Include="TUnit.Mocks" Version="1.73.19" />
</ItemGroup>
</Project>using TUnit.Mocks;
public interface ICalculator { int Add(int a, int b); }
public interface IRepository<T> { T? Find(int id); }
public class MockTests
{
[Test]
public async Task Basic()
{
var mock = Mock.Of<ICalculator>();
mock.Add(1, 2).Returns(3);
await Assert.That(mock.Object.Add(1, 2)).IsEqualTo(3);
}
[Test]
public async Task Generic() // causes the IL2069 warnings
{
var mock = Mock.Of<IRepository<string>>();
mock.Find(1).Returns("one");
await Assert.That(mock.Object.Find(1)).IsEqualTo("one");
}
}dotnet publish -c Release -r linux-x64 -p:TrimmerSingleWarn=false
TUnit Version
1.73.19
.NET Version
.NET 10 (SDK 10.0.401), .NET 11 RC1
Operating System
Linux
IDE / Test Runner
dotnet CLI (dotnet test / dotnet run)
Error Output / Stack Trace
Generating native code
ILC : Trim analysis warning IL2069: TUnit.Mocks.MockRegistry.OpenGenericFactoryDescriptor.OpenGenericFactoryDescriptor(Type,Type): value stored in field 'TUnit.Mocks.MockRegistry.OpenGenericFactoryDescriptor.<OpenImplementationType>k__BackingField' does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors' requirements. The parameter 'OpenImplementationType' of method 'TUnit.Mocks.MockRegistry.OpenGenericFactoryDescriptor.OpenGenericFactoryDescriptor(Type,Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [/home/fubar-coder/Projekte/Tests/TrimTestWarnings/test.csproj]
ILC : Trim analysis warning IL2069: TUnit.Mocks.MockRegistry.OpenGenericFactoryDescriptor.OpenGenericFactoryDescriptor(Type,Type): value stored in field 'TUnit.Mocks.MockRegistry.OpenGenericFactoryDescriptor.<OpenWrapperType>k__BackingField' does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors' requirements. The parameter 'OpenWrapperType' of method 'TUnit.Mocks.MockRegistry.OpenGenericFactoryDescriptor.OpenGenericFactoryDescriptor(Type,Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. [/home/fubar-coder/Projekte/Tests/TrimTestWarnings/test.csproj]
ILC : Trim analysis warning IL2026: TUnit.Mocks.MockEngine`1.HandleCallWithReturn<TReturn,T1>(Int32,String,T1,!!0): Using member 'TUnit.Mocks.IDefaultValueProvider.GetDefaultValue(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Implementations may use reflection to construct types at runtime. [/home/fubar-coder/Projekte/Tests/TrimTestWarnings/test.csproj]
ILC : AOT analysis warning IL3050: TUnit.Mocks.MockEngine`1.HandleCallWithReturn<TReturn,T1>(Int32,String,T1,!!0): Using member 'TUnit.Mocks.IDefaultValueProvider.GetDefaultValue(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Implementations may use MakeGenericMethod or Activator.CreateInstance. AOT-safe implementations can override without these. [/home/fubar-coder/Projekte/Tests/TrimTestWarnings/test.csproj]
ILC : Trim analysis warning IL2026: TUnit.Mocks.MockEngine`1.HandleCallWithReturn<TReturn,T1,T2>(Int32,String,T1,T2,!!0): Using member 'TUnit.Mocks.IDefaultValueProvider.GetDefaultValue(Type)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Implementations may use reflection to construct types at runtime. [/home/fubar-coder/Projekte/Tests/TrimTestWarnings/test.csproj]
ILC : AOT analysis warning IL3050: TUnit.Mocks.MockEngine`1.HandleCallWithReturn<TReturn,T1,T2>(Int32,String,T1,T2,!!0): Using member 'TUnit.Mocks.IDefaultValueProvider.GetDefaultValue(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Implementations may use MakeGenericMethod or Activator.CreateInstance. AOT-safe implementations can override without these. [/home/fubar-coder/Projekte/Tests/TrimTestWarnings/test.csproj]
ILC : AOT analysis warning IL3050: TUnit.Mocks.MockRegistry.CreateClosedGenericMock(Type,MockBehavior,Object[],MockRegistry.OpenGenericFactoryDescriptor): Using member 'System.Type.MakeGenericType(Type[])' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. The native code for this instantiation might not be available at runtime. [/home/fubar-coder/Projekte/Tests/TrimTestWarnings/test.csproj]
ILC : Trim analysis warning IL2055: TUnit.Mocks.MockRegistry.CreateClosedGenericMock(Type,MockBehavior,Object[],MockRegistry.OpenGenericFactoryDescriptor): Call to 'System.Type.MakeGenericType(Type[])' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. [/home/fubar-coder/Projekte/Tests/TrimTestWarnings/test.csproj]
ILC : AOT analysis warning IL3050: TUnit.Mocks.MockRegistry.CreateClosedGenericMock(Type,MockBehavior,Object[],MockRegistry.OpenGenericFactoryDescriptor): Using member 'System.Type.MakeGenericType(Type[])' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. The native code for this instantiation might not be available at runtime. [/home/fubar-coder/Projekte/Tests/TrimTestWarnings/test.csproj]
ILC : Trim analysis warning IL2055: TUnit.Mocks.MockRegistry.CreateClosedGenericMock(Type,MockBehavior,Object[],MockRegistry.OpenGenericFactoryDescriptor): Call to 'System.Type.MakeGenericType(Type[])' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. [/home/fubar-coder/Projekte/Tests/TrimTestWarnings/test.csproj]Simpler excerpt:
IL3050: TUnit.Mocks.MockEngine`1.HandleCallWithReturn<TReturn,T1,T2>(...): Using member 'TUnit.Mocks.IDefaultValueProvider.GetDefaultValue(Type)' which has 'RequiresDynamicCodeAttribute' ...
IL2026: TUnit.Mocks.MockEngine`1.HandleCallWithReturn<TReturn,T1,T2>(...): Using member 'TUnit.Mocks.IDefaultValueProvider.GetDefaultValue(Type)' which has 'RequiresUnreferencedCodeAttribute' ...
IL3050: TUnit.Mocks.MockRegistry.CreateClosedGenericMock(...): Using member 'System.Type.MakeGenericType(Type[])' which has 'RequiresDynamicCodeAttribute' ...
IL2055: TUnit.Mocks.MockRegistry.CreateClosedGenericMock(...): Call to 'System.Type.MakeGenericType(Type[])' can not be statically analyzed ...
IL2069: TUnit.Mocks.MockRegistry.OpenGenericFactoryDescriptor.OpenGenericFactoryDescriptor(Type,Type): value stored in field '<OpenImplementationType>k__BackingField' does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors' requirements ...
IL2069: (same for '<OpenWrapperType>k__BackingField')Additional Context
Yes, Native AOT. For now we downgrade these warnings in our test projects with WarningsNotAsErrors.
IDE-Specific Issue?
- I've confirmed this issue occurs when running via
dotnet testordotnet run, not just in my IDE
Activity
fix(mocks): pre-register closed generic mocks and guard AOT warnings …
fix(mocks): eliminate trim/AOT warnings on Native AOT publish (thomhu…