c# - 如何对 Roslyn 诊断进行单元测试?

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

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

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

最佳答案

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

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

我提出了两种解决方案:

  1. 通读这篇博文的其余部分,其中我对这些类(class)中正在做的事情以及它们的关键方面进行了广泛的布局。之后,您可以根据需要创建自己的实现。

  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 .

关于c# - 如何对 Roslyn 诊断进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30384868/

相关文章:

c# - 如何将可为空的 int 转换为对不同区域设置的计算机安全的字符串?

unit-testing - 有没有办法仅在新代码上获得单位覆盖率(例如来自 jacoco)?

java - Spring 3.1 和 Hibernate 4 : "HibernateException: No Session found for current thread" When calling DAO method from unit test

java - 同时测试 Clojure 和 Java

.net - Nuget 3 - Octopack - 框架目标错误错误

tfs - VS2015 缺少禁止模式策略?

c++ - 设置一个项目,该项目将使用和不使用预编译头文件进行编译

c# - 如何在 visual studio 2015 中管理 EF 6 迁移?

c# - 从url读取Json,无需下载

c# - 如何使 WPF 数据绑定(bind)重构安全?