C# Roslyn如何测试特定属性类型的检查
TL;DR:在Roslyn中,我想知道如何根据已知类型测试属性的类型 我遵循了这一点,它基本上涉及到使用名为“Analyzer with code fix(.NET Standard)”的VisualStudio模板项目。该模板为您提供了一个Analyzer项目(包括一个工作的Analyzer和它的“代码修复”),以及一个单元测试项目(其中一些类提供了测试Analyzer和“代码修复”的框架)和一个VSIX项目。非常好:谢谢微软 我现在正试着写我的第一个分析器,我在第一个关卡上摔倒了。我正在尝试创建一个分析器,该分析器检查使用某些类型进行属性化的方法是否与属性类型名称具有相同的名称。我计划用它来确保NUnit[Setup]方法被称为“Setup”;[TearDown]方法被称为“TearDown”,等等。。。方法的名称与附加到该方法的属性的名称相同 我已经看过了;但答案实际上并没有在问题的上下文中使用(它没有提到如何将C# Roslyn如何测试特定属性类型的检查,c#,unit-testing,attributes,roslyn,C#,Unit Testing,Attributes,Roslyn,TL;DR:在Roslyn中,我想知道如何根据已知类型测试属性的类型 我遵循了这一点,它基本上涉及到使用名为“Analyzer with code fix(.NET Standard)”的VisualStudio模板项目。该模板为您提供了一个Analyzer项目(包括一个工作的Analyzer和它的“代码修复”),以及一个单元测试项目(其中一些类提供了测试Analyzer和“代码修复”的框架)和一个VSIX项目。非常好:谢谢微软 我现在正试着写我的第一个分析器,我在第一个关卡上摔倒了。我正在尝试
desiredSymbol
与attr
进行比较-我假设它们不会是“ReferenceEquals”);不管怎么说,我的处境因为一个次要问题而变得更加复杂
当我在运行单元测试时使用调试器查看x.AttributeClass
时,属性的类型名称前面有“ErrorType”,因此我假设它无法解析该类型;因此,我更改了模板项目中提供的测试框架中使用的引用,通过在相关位置添加以下两行来更改“DiagnosticVerifier.Helper.cs”“CreateProject”方法:
private static readonly MetadataReference NUnitReference = MetadataReference.CreateFromFile(typeof(NUnit.Framework.SetUpAttribute).Assembly.Location);
及
这修复了symbolsToCheckFor
中的项,这些项现在可以正确解析,而不是为空
很难为这样的东西提供MCVE;但以下是我的诊断分析仪:
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class MethodAnalyzer : DiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rules.CO1000_UseAttributeNameForSetUpAndTearDown);
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(AnalyzeMethod, SymbolKind.Method);
}
private static void AnalyzeMethod(SymbolAnalysisContext context)
{
var symbol = (IMethodSymbol)context.Symbol;
var symbolsToCheckFor = new[]
{
context.Compilation.GetTypeByMetadataName("NUnit.Framework.SetUpAttribute"),
context.Compilation.GetTypeByMetadataName("NUnit.Framework.TearDownAttribute"),
context.Compilation.GetTypeByMetadataName("NUnit.Framework.OneTimeSetUpAttribute"),
context.Compilation.GetTypeByMetadataName("NUnit.Framework.OneTimeTearDownAttribute")
};
var first = symbol.GetAttributes().FirstOrDefault(x => symbolsToCheckFor.Contains(x.AttributeClass));
if (first != null)
{
var expectedName = Regex.Replace(first.AttributeClass.Name, "Attribute$", string.Empty);
if (symbol.Name != expectedName)
{
var diagnostic = Diagnostic.Create(Rules.CO1000_UseAttributeNameForSetUpAndTearDown, symbol.Locations[0], symbol.Name, expectedName);
context.ReportDiagnostic(diagnostic);
}
}
}
编辑
我现在发现我一个月前发布的代码在实际使用时基本上是有效的。问题是,完全与测试有关。。。因此,我需要帮助找出如何使测试通过,因为代码在实际使用时实际工作
感谢您的帮助
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class MethodAnalyzer : DiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rules.CO1000_UseAttributeNameForSetUpAndTearDown);
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(AnalyzeMethod, SymbolKind.Method);
}
private static void AnalyzeMethod(SymbolAnalysisContext context)
{
var symbol = (IMethodSymbol)context.Symbol;
var symbolsToCheckFor = new[]
{
context.Compilation.GetTypeByMetadataName("NUnit.Framework.SetUpAttribute"),
context.Compilation.GetTypeByMetadataName("NUnit.Framework.TearDownAttribute"),
context.Compilation.GetTypeByMetadataName("NUnit.Framework.OneTimeSetUpAttribute"),
context.Compilation.GetTypeByMetadataName("NUnit.Framework.OneTimeTearDownAttribute")
};
var first = symbol.GetAttributes().FirstOrDefault(x => symbolsToCheckFor.Contains(x.AttributeClass));
if (first != null)
{
var expectedName = Regex.Replace(first.AttributeClass.Name, "Attribute$", string.Empty);
if (symbol.Name != expectedName)
{
var diagnostic = Diagnostic.Create(Rules.CO1000_UseAttributeNameForSetUpAndTearDown, symbol.Locations[0], symbol.Name, expectedName);
context.ReportDiagnostic(diagnostic);
}
}
}
[TestCase("SetUp")]
[TestCase("TearDown")]
[TestCase("OneTimeSetUp")]
[TestCase("OneTimeTearDown")]
[TestCase("NUnit.Framework.SetUp")]
[TestCase("NUnit.Framework.TearDown")]
[TestCase("NUnit.Framework.OneTimeSetUp")]
[TestCase("NUnit.Framework.OneTimeTearDown")]
public void Diagnostic_triggered_correctly(string attributeName)
{
const string faultyMethodName = "MyMethod";
var test = $@"
using NUnit.Framework;
namespace ConsoleApplication1
{{
[TestFixture]
public class MyTests
{{
[{attributeName}]
public void {faultyMethodName}()
{{
}}
}}
}}";
string expectedMethodName = attributeName;
int lastDot = expectedMethodName.LastIndexOf('.');
if (lastDot != -1)
{
expectedMethodName = expectedMethodName.Substring(lastDot + 1);
}
var expected = new DiagnosticResult
{
Id = Rules.CO1000_UseAttributeNameForSetUpAndTearDown.Id,
Message = $"Method name '{faultyMethodName}' should match the attribute name '{expectedMethodName}'",
Severity = DiagnosticSeverity.Warning,
Locations =
new[] {
new DiagnosticResultLocation("Test0.cs", 11, 15)
}
};
VerifyCSharpDiagnostic(test, expected);
}