Jam*_*aix 6 c# unit-testing precompile roslyn
背景
我正在使用StackExchange.Precompilation在C#中实现面向方面的编程. 在GitHub上查看我的存储库.
基本思想是客户端代码将能够在成员上放置自定义属性,预编译器将对具有这些属性的任何成员执行语法转换.NonNullAttribute
我创建了一个简单的例子.何时NonNullAttribute
放置参数p
,预编译器将插入
if (Object.Equals(p, null)) throw new ArgumentNullException(nameof(p));
Run Code Online (Sandbox Code Playgroud)
在方法体的开头.
诊断很棒......
我想让错误地使用这些属性变得困难.我发现的最好的方法(除了直观设计)是Diagnostic
为了无效或不合逻辑地使用属性创建编译时间.
例如,NonNullAttribute
对值类型成员使用没有意义.(即使对于可以为空的值类型,因为如果你想保证它们不是null,那么应该使用非可空类型.)创建Diagnostic
一个很好的方法来告知用户这个错误,而不会像这样构建崩溃一个例外.
......但我该如何测试它们?
诊断是突出错误的好方法,但我也想确保我的诊断创建代码没有错误.我希望能够设置一个可以预编译这样的代码示例的单元测试
public class TestClass {
public void ShouldCreateDiagnostic([NonNull] int n) { }
}
Run Code Online (Sandbox Code Playgroud)
并确认已创建正确的诊断(或在某些情况下未创建诊断).
任何熟悉StackExchange.Precompilation的人都可以给我一些指导吗?
解:
@ m0sa给出的答案非常有帮助.实现有很多细节,所以这里的单元测试看起来很像(使用NUnit 3).注意using static
for SyntaxFactory
,这消除了语法树构造中的大量混乱.
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using NUnit.Framework;
using StackExchange.Precompilation;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace MyPrecompiler.Tests {
[TestFixture]
public class NonNull_CompilationDiagnosticsTest {
[Test]
public void NonNullAttribute_CreatesDiagnosticIfAppliedToValueTypeParameter() {
var context = new BeforeCompileContext {
Compilation = TestCompilation_NonNullOnValueTypeParameter(),
Diagnostics = new List<Diagnostic>()
};
ICompileModule module = new MyPrecompiler.MyModule();
module.BeforeCompile(context);
var diagnostic = context.Diagnostics.SingleOrDefault();
Assert.NotNull(diagnostic);
Assert.AreEqual("MyPrecompiler: Invalid attribute usage",
diagnostic.Descriptor.Title.ToString()); //Must use ToString() because Title is a LocalizeableString
}
//Make sure there are spaces before the member name, parameter names, and parameter types.
private CSharpCompilation TestCompilation_NonNullOnValueTypeParameter() {
return CreateCompilation(
MethodDeclaration(ParseTypeName("void"), Identifier(" TestMethod"))
.AddParameterListParameters(
Parameter(Identifier(" param1"))
.WithType(ParseTypeName(" int"))
.AddAttributeLists(AttributeList()
.AddAttributes(Attribute(ParseName("NonNull"))))));
}
//Make sure to include Using directives
private CSharpCompilation CreateCompilation(params MemberDeclarationSyntax[] members) {
return CSharpCompilation.Create("TestAssembly")
.AddReferences(References)
.AddSyntaxTrees(CSharpSyntaxTree.Create(CompilationUnit()
.AddUsings(UsingDirective(ParseName(" Traction")))
.AddMembers(ClassDeclaration(Identifier(" TestClass"))
.AddMembers(members))));
}
private string runtimePath = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\";
private MetadataReference[] References =>
new[] {
MetadataReference.CreateFromFile(runtimePath + "mscorlib.dll"),
MetadataReference.CreateFromFile(runtimePath + "System.dll"),
MetadataReference.CreateFromFile(runtimePath + "System.Core.dll"),
MetadataReference.CreateFromFile(typeof(NonNullAttribute).Assembly.Location)
};
}
}
Run Code Online (Sandbox Code Playgroud)
我认为您想在实际发出/编译之前添加诊断,因此步骤是:
CSharpCompilation
,在进一步操作之前确保它没有诊断错误BeforeCompileContext
,并用编译和一个空的填充它List<Diagnostic>
ICompileModule
并ICompileModule.BeforeCompile
使用步骤 2 中的上下文进行调用Diagnostic
归档时间: |
|
查看次数: |
108 次 |
最近记录: |