在询问了关于使用PostSharp实现方面的question之后,我想到未来可能需要更新此方面的代码,而且我不想冒破坏一切的风险。因此,我开始考虑单元测试。我的第一个问题是:是否有必要考虑对一个方面进行单元测试?我希望答案是“是”,但如果不是,我希望得到其他建议。然后,如果是这样的话,如何为PostSharp方面实现单元测试?请注意,保留html标记。
在单元测试中测试方面确实是有意义的,因为它们代表功能,并且由于您在多个地方使用它,因此测试它变得更加重要。
但是您必须将其分为两部分:
对于第一部分,如果您已将实际功能与执行方面功能的属性解耦,则创建单元测试与单元测试常规代码没有区别。
对于第二部分,您还需要解耦上下文提取,这可能看起来有些杀鸡焉用牛刀,但如果您想正确地进行单元测试,就需要做这件事情。
在这个过程中,您还应该利用编译时验证,它可以防止您以错误的方式使用属性。有时需要测试某些无法用属性语法描述的条件,这时就需要使用编译时验证。对我来说,这非常有帮助,大大减少了关于PostSharp方面的调试会话数量,详情请参见:
http://www.sharpcrafters.com/postsharp/robustness
以下是一些非常基本的示例代码,没有任何依赖注入,只是为了说明如何将事情拆分:
public sealed class TraceAttribute : OnMethodBoundaryAspect
{
private readonly string category;
private TraceArgumentService argumentService;
private TraceService traceService;
public string Category { get { return category; } }
public TraceAttribute(string category)
{
this.category = category;
}
public override void RuntimeInitialize(System.Reflection.MethodBase method)
{
base.RuntimeInitialize(method);
this.argumentService = new TraceArgumentService();
this.traceService = new TraceService();
}
public override void OnEntry(MethodExecutionArgs args)
{
traceService.Write(
argumentService.GetDeclaringTypeName(args),
argumentService.GetMethodName(args),
category);
}
}
public class TraceArgumentService
{
public string GetDeclaringTypeName(MethodExecutionArgs args)
{
return args.Method.DeclaringType.Name;
}
public string GetMethodName(MethodExecutionArgs args)
{
return args.Method.Name;
}
}
public class TraceService
{
public void Write(string declaringTypeName, string methodName, string category)
{
Trace.WriteLine(string.Format("Entering {0}.{1}.",
declaringTypeName, methodName), category);
}
}
你可能会问为什么要使用TraceService
和单独的TraceArgumentService
:
MethodExecutionArgs
。MethodExecutionArgs
中提取参数并不是跟踪的一部分,它更多地与方面相关。由于您希望能够对其进行测试,因此需要以某种方式将其分离。