【发布时间】:2015-05-21 21:42:26
【问题描述】:
如何对我自己的自定义分析器和代码修复提供程序进行单元测试?
我正坐在电脑前,双手放在键盘上,但我不知道该输入什么。
【问题讨论】:
标签: c# unit-testing visual-studio-2015 roslyn
如何对我自己的自定义分析器和代码修复提供程序进行单元测试?
我正坐在电脑前,双手放在键盘上,但我不知道该输入什么。
【问题讨论】:
标签: c# unit-testing visual-studio-2015 roslyn
一个好的开始是使用“诊断和代码修复”模板创建一个新的解决方案。这将创建一个带有一些类的单元测试项目,这些类允许您非常轻松地测试您的诊断。
然而,这也显示了它的弱点:类在您的代码库中是硬编码的,而不是您可以在需要时轻松更新的依赖项。在像 Roslyn 这样不断变化的代码库中,这意味着您将很快落后:测试类针对的是 Beta-1,而 Roslyn 在撰写本文时已经是 RC2。
我提出了两种解决方案:
通读这篇文章的其余部分,我对这些课程的内容及其关键方面进行了广泛的布局。之后,您可以根据需要创建自己的实现。
删除所有这些类,改为使用我基于这些帮助程序创建的RoslynTester NuGet 包。这将允许您立即开始使用 Roslyn 的 RC2 版本并使其更易于更新。如需更多信息,请查看my blog 或the 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 repository 或my blogpost on writing your own。
【讨论】:
使用模板项目提供的默认基础架构测试分析器相当复杂。 Dustin Campbell 创建了一个很好的项目 RoslynNUnitLight,它使 Roslyn 分析器的测试、代码修复和重构变得超级容易。不幸的是,它不再维护。我创建了一个分支并进行了一些调整,例如:
这个分支叫做 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
【讨论】:
有来自 Microsoft 的 Microsoft.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 包管理器添加/更新这些包时,您可能必须包括预发布版。
这些包支持测试DiagnosticAnalyzer、CodeFixProvider和CodeRefactoringProvider,
用 C# 或 Visual Basic 编写,
通过 MSTest V2、NUnit 或 xUnit.net,
通过添加特定的PackageReference:
Microsoft.CodeAnalysis.[CSharp|VisualBasic].[Analyzer|CodeFix|CodeRefactoring].Testing.[MSTest|NUnit|XUnit]
目前不支持测试CompletionProvider。
警告:Visual Studio 16.6 模板包含错误,无法编译。 有关正确的命名空间和方法名称,请参阅 documentation。
【讨论】: