C# Roslyn源代码生成器运行正常但单元测试无法生成预期代码
Roslyn源代码生成器测试异常问题
问题背景
开发的简单Roslyn增量源代码生成器在实际项目中可正常生成代码,但编写的单元测试无法触发预期的代码生成逻辑,表现为谓词返回true却未进入transform环节。
生成器代码
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; using System.Text; namespace TestGenerator; [Generator] public class TestGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { var classDeclarations = context.SyntaxProvider.ForAttributeWithMetadataName( "TestGenerator.TestSourceGeneratorAttribute", predicate: static (s, _) => (s is ClassDeclarationSyntax || s is StructDeclarationSyntax) && s is TypeDeclarationSyntax type && type.Modifiers.Any(SyntaxKind.PartialKeyword), transform: static (ctx, _) => { if (ctx.TargetNode is TypeDeclarationSyntax typeDeclarationSyntax) { return typeDeclarationSyntax.Identifier.ToString(); } return null; }) .Where(static m => m is not null); var compilationAndClasses = classDeclarations.Collect(); context.RegisterSourceOutput(compilationAndClasses, static (spc, classes) => { foreach (var typeDefinition in classes) { spc.AddSource($"{typeDefinition}.g.cs", SourceText.From(GetSource(typeDefinition), Encoding.UTF8)); } }); } private static string GetSource(string source) { return $@" //<auto-generated/> #nullable enable using System; /// {source} "; } }
项目内正常运行示例
项目中添加测试类:
namespace TestGenerator.Test { [TestSourceGenerator] public partial class TestClassGenerated { } }
可正常生成代码:
//<auto-generated/> #nullable enable using System; /// TestClassGenerated
单元测试代码
using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Testing; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Threading.Tasks; namespace TestGenerator.Test; [TestClass] public class TestGeneratorUnitTest { [TestMethod] public async Task Test123() { var source = @" using System; namespace TestGenerator.Test { [TestSourceGenerator] public partial class MyClass { } } "; var expectedGeneratedCode = @" //<auto-generated/> #nullable enable using System; /// MyClass "; var test = new CSharpSourceGeneratorTest<TestGenerator, DefaultVerifier> { TestState = { Sources = { source }, GeneratedSources = { (typeof(TestGenerator), "MyClass.g.cs", expectedGeneratedCode) } } }; await test.RunAsync(); } }
问题原因
测试代码的source仅引用了[TestSourceGenerator]属性,但未在测试的编译环境中提供该属性的定义。ForAttributeWithMetadataName依赖元数据匹配属性,测试环境无法找到对应属性的元数据,导致即使语法层面匹配(谓词返回true),也无法进入transform阶段。
解决方案
- 在测试的
source中添加TestSourceGeneratorAttribute的完整定义,确保测试编译环境能识别该属性:
var source = @" using System; namespace TestGenerator { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] sealed class TestSourceGeneratorAttribute : Attribute { } } namespace TestGenerator.Test { [TestSourceGenerator] public partial class MyClass { } } ";
- 调整预期代码的格式,确保与生成器输出完全一致(避免缩进、换行差异导致测试失败):
var expectedGeneratedCode = @" //<auto-generated/> #nullable enable using System; /// MyClass ";
内容的提问来源于stack exchange,提问作者Luiz Bicalho
相关产品推荐
相关产品推荐

