【问题标题】:How can I unit test Roslyn diagnostics?如何对 Roslyn 诊断进行单元测试?
【发布时间】:2015-05-21 21:42:26
【问题描述】:

如何对我自己的自定义分析器和代码修复提供程序进行单元测试?

我正坐在电脑前,双手放在键盘上,但我不知道该输入什么。

【问题讨论】:

    标签: c# unit-testing visual-studio-2015 roslyn


    【解决方案1】:

    一个好的开始是使用“诊断和代码修复”模板创建一个新的解决方案。这将创建一个带有一些类的单元测试项目,这些类允许您非常轻松地测试您的诊断。

    然而,这也显示了它的弱点:类在您的代码库中是硬编码的,而不是您可以在需要时轻松更新的依赖项。在像 Roslyn 这样不断变化的代码库中,这意味着您将很快落后:测试类针对的是 Beta-1,而 Roslyn 在撰写本文时已经是 RC2。

    我提出了两种解决方案:

    1. 通读这篇文章的其余部分,我对这些课程的内容及其关键方面进行了广泛的布局。之后,您可以根据需要创建自己的实现。

    2. 删除所有这些类,改为使用我基于这些帮助程序创建的RoslynTester NuGet 包。这将允许您立即开始使用 Roslyn 的 RC2 版本并使其更易于更新。如需更多信息,请查看my blogthe Github page


    想法

    帮助器背后的想法很简单:给定一个或多个表示类文件的字符串和一个或多个表示预期诊断结果的对象,使用给定的类创建一个内存项目并执行分析器。

    对于 CodeFix 提供程序,您还可以指定代码在转换后的外观。

    执行

    怎么称呼?

    这是一个示例测试,当您有一个名称不以“Async”结尾的异步方法并提供一个 CodeFix 来更改名称时,它会显示警告。

    [TestMethod]
    public void AsyncMethodWithoutAsyncSuffixAnalyzer_WithAsyncKeywordAndNoSuffix_InvokesWarning()
    {
        var original = @"
    using System;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
       class MyClass
       {   
           async Task Method()
           {
    
           }
       }
    }";
    
        var result = @"
    using System;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
       class MyClass
       {   
           async Task MethodAsync()
           {
    
           }
       }
    }";
    
        var expectedDiagnostic = new DiagnosticResult
        {
            Id = AsyncMethodWithoutAsyncSuffixAnalyzer.DiagnosticId,
            Message = string.Format(AsyncMethodWithoutAsyncSuffixAnalyzer.Message, "Method"),
            Severity = EmptyArgumentExceptionAnalyzer.Severity,
            Locations =
            new[]
            {
                new DiagnosticResultLocation("Test0.cs", 10, 13)
            }
        };
    
        VerifyCSharpDiagnostic(original, expectedDiagnostic);
        VerifyCSharpFix(original, result);
    }
    

    如您所见,设置非常简单:您确定错误代码的外观,指定它的外观,并指明应该显示的警告的属性。

    创建项目

    第一步是创建内存项目。这包括几个步骤:

    • 创建工作区 (new AdhocWorkspace())
    • 向其中添加一个新项目 (.CurrentSolution.AddProject())
    • 添加对相关程序集的引用 (.AddMetadataReferences())
    • 向解决方案添加文档(solution.AddDocument())

    收集诊断信息

    这里我们将使用我们刚刚创建的文档。这两行是最重要的:

    var compilation = project.GetCompilationAsync().Result;
    var diagnostics = compilation.WithAnalyzers(ImmutableArray.Create(analyzer))
                                 .GetAnalyzerDiagnosticsAsync()
                                 .Result;
    

    验证诊断

    此时,您拥有所需的一切:您拥有实际结果和预期结果。剩下的就是验证两个集合是否匹配。

    应用代码修复

    这大致遵循与诊断相同的模式,但增加了一点。

    • 创建文档
    • 获取分析仪
    • 创建一个CodeFixContext
    var actions = new List<CodeAction>();
    var context = new CodeFixContext(document, analyzerDiagnostics[0], 
                  (a, d) => actions.Add(a), CancellationToken.None);
    codeFixProvider.RegisterCodeFixesAsync(context).Wait();
    
    • 应用代码修复
    var operations = codeAction.GetOperationsAsync(CancellationToken.None).Result;
    var solution = operations.OfType<ApplyChangesOperation>().Single().ChangedSolution;
    
    • 可选:验证没有因重构而触发新诊断
    • 验证预期来源和结果来源是否相同

    如果一切还是有点模糊,一定要看看the exact source code。如果您想更清楚地了解如何创建自己的诊断程序,请查看my VSDiagnostics repositorymy blogpost on writing your own

    【讨论】:

      【解决方案2】:

      使用模板项目提供的默认基础架构测试分析器相当复杂。 Dustin Campbell 创建了一个很好的项目 RoslynNUnitLight,它使 Roslyn 分析器的测试、代码修复和重构变得超级容易。不幸的是,它不再维护。我创建了一个分支并进行了一些调整,例如:

      • 从单元测试框架中删除了依赖项。现在您可以使用自己喜欢的框架创建测试:xunit、nunit、mstest 等。
      • 增加了通过行号定位诊断位置的功能
      • 添加了用于测试 CompletionProviders 的基础架构
      • 改进的错误消息
      • 在调试模式下使用差异工具呈现代码差异

      这个分支叫做 RoslynTestKit,它可以在 GitHub https://github.com/cezarypiatek/RoslynTestKit 上找到

      Nuget 包:https://www.nuget.org/packages/SmartAnalyzers.RoslynTestKit/

      您可以在此项目中找到使用 RoslynTestKit 构建的示例测试 https://github.com/smartanalyzers/MultithreadingAnalyzer/tree/master/src/MultithreadingAnalyzer.Test

      【讨论】:

        【解决方案3】:

        有来自 MicrosoftMicrosoft.CodeAnalysis.Testing (GitHub) 包, 目前预发布版本在MyGet 上可用。 这些也包含在 Visual Studio 16.6 模板Analyzer with Code Fix (.NET Standard)中。

        为了使用这些包,您必须将它们的 包源 添加到 NuGet 配置文件: 转到/configuration/packageSources 并添加:

        <add key="roslyn-analyzers" value="https://dotnet.myget.org/F/roslyn-analyzers/api/v3/index.json" />
        

        如果您还没有NuGet 配置文件,您可以使用dotnet new nugetconfig 创建一个新文件。

        使用 NuGet 包管理器添加/更新这些包时,您可能必须包括预发布版

        这些包支持测试DiagnosticAnalyzerCodeFixProviderCodeRefactoringProvider, 用 C#Visual Basic 编写, 通过 MSTest V2NUnitxUnit.net, 通过添加特定的PackageReference:

        Microsoft.CodeAnalysis.[CSharp|VisualBasic].[Analyzer|CodeFix|CodeRefactoring].Testing.[MSTest|NUnit|XUnit]
        

        目前不支持测试CompletionProvider

        警告Visual Studio 16.6 模板包含错误,无法编译。 有关正确的命名空间和方法名称,请参阅 documentation

        【讨论】:

          猜你喜欢
          • 2017-04-29
          • 1970-01-01
          • 1970-01-01
          • 2012-01-08
          • 1970-01-01
          • 2019-11-02
          • 1970-01-01
          • 1970-01-01
          • 2013-09-30
          相关资源
          最近更新 更多