如何将DI框架中的AOP与C#TestFrameworks结合使用?(不适用于测试项目)
我为一个糟糕的标题提前道歉-欢迎建议 我一直在读关于DI和AOP的书,我想我掌握了基本知识;至少对于添加日志记录的规范示例是这样的 我想将此应用于我们在NUnit中创建的测试用例,例如,能够自动为所有测试用例方法和它们调用的任何“助手方法”添加入口/出口日志记录。(我与NUnit没有关系——如果在另一个框架中更容易,请让我知道。) 注-这与受试者无关;我想将这些技术应用于测试用例本身 这是非常清楚的如何做到这一点使用-这是他们的,但我不想添加他们的许可证处理到我们的项目只是为了这个实验 我在AOP for C#中找到的所有其他参考都是基于IoC容器实现提供的(动态)拦截器,如CastleWindsor、Unity、Spring.Net等等。。。在这种情况下,它们都有一个共同的问题:您需要一段设置代码来为要添加拦截器的对象创建代理。(我原本认为这段代码还必须创建一个IoC容器,但我发现我错了。) 但是我看不出nUnit测试用例的设置代码会用到哪里 我提出的选项及其问题:如何将DI框架中的AOP与C#TestFrameworks结合使用?(不适用于测试项目),c#,dependency-injection,nunit,aop,mbunit,C#,Dependency Injection,Nunit,Aop,Mbunit,我为一个糟糕的标题提前道歉-欢迎建议 我一直在读关于DI和AOP的书,我想我掌握了基本知识;至少对于添加日志记录的规范示例是这样的 我想将此应用于我们在NUnit中创建的测试用例,例如,能够自动为所有测试用例方法和它们调用的任何“助手方法”添加入口/出口日志记录。(我与NUnit没有关系——如果在另一个框架中更容易,请让我知道。) 注-这与受试者无关;我想将这些技术应用于测试用例本身 这是非常清楚的如何做到这一点使用-这是他们的,但我不想添加他们的许可证处理到我们的项目只是为了这个实验 我在AO
有没有我错过的更简单的方法呢?面向方面编程不仅仅是使用动态代理(拦截)或编译后代码编织(PostSharp)。AOP主要是关于添加横切关注点。使用动态代理是添加横切关注点的一种方法。代码编织是实现这一点的另一种方法。但还有另一种更好的方式来增加交叉关注点 不要使用动态代理或代码编织,而是让应用程序的设计引导您。当您使用正确的抽象设计应用程序时,使用decorator添加横切关注点是很容易的。您可以找到使用适当的抽象和设计的系统示例 这些文章描述了如何使用装饰器定义横切关注点。以这种方式设计系统时,可以从代码的其余部分中分别测试横切关注点的实现。当使用正确的抽象时,这将很容易 当您这样做时,不需要在单元测试中做任何特殊的事情。不需要代码编织,也不需要在测试中运行DI容器来为您构建对象。您可以测试您的应用程序逻辑,而无需任何横切问题。您可以单独测试每个小部件,并将所有部件放在应用程序的中。这里是一个使用(通过在测试项目上安装+numets)的示例
使用系统;
使用System.Collections.Generic;
使用System.Linq;
运用系统反思;
使用System.Threading.Tasks;
使用NUnit.Framework;
使用Puresharp;
名称空间测试
{
///
///类以使用NUnit进行测试
///
公共类计算器
{
公共整数相加(整数a、整数b)
{
返回a+b;
}
}
///
///一个简单的计算器测试类。
///
[测试夹具]
公共类计算器测试
{
///
///将方面附加到测试方法的静态构造函数(类构造函数)。
///
静态计算器测试()
{
//实例化我的自定义方面。
var myBasicAspect=新的mucustomspect();
//将自定义特性附加到自定义切入点
myBasicAspect.Weave();
}
[测试]
public void应添加两个数字()
{
var_calculator=新计算器();
int _result=_calculator.Add(2,8);
断言(_result,Is.EqualTo(10));
}
}
///
///切入点用于确定要编织的方法组(此处为CalculatorTest的测试方法)。
///
公共类MyCustomPointcut:切入点
{
重写公共布尔匹配(MethodBase方法)
{
return method.DeclaringType==typeof(CalculatorTest)和&method.GetCustomAttributes(typeof(TestAttribute),true).Any();
}
}
///
///这是一个很好的方面。
///
公共类mucustomspect:方面
{
公共重写IEnumerable管理(MethodBase方法)
{
//Aspect将使用MyCustomAdvice在边界上通知方法。
收益率
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using NUnit.Framework;
using Puresharp;
namespace TEST
{
/// <summary>
/// Class to test with NUnit
/// </summary>
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
}
/// <summary>
/// Test class for calculator with a simple test.
/// </summary>
[TestFixture]
public class CalculatorTest
{
/// <summary>
/// Static constructor (class constructor) to attach aspect to test method.
/// </summary>
static CalculatorTest()
{
//Instantiate my custom aspect.
var myBasicAspect = new MuCustomAspect();
//Attach my custom aspect to my custom pointcut
myBasicAspect.Weave<MyCustomPointcut>();
}
[Test]
public void ShouldAddTwoNumbers()
{
var _calculator = new Calculator();
int _result = _calculator.Add(2, 8);
Assert.That(_result, Is.EqualTo(10));
}
}
/// <summary>
/// Pointcut to identify methods group to weave (here test methods of CalculatorTest).
/// </summary>
public class MyCustomPointcut : Pointcut
{
override public bool Match(MethodBase method)
{
return method.DeclaringType == typeof(CalculatorTest) && method.GetCustomAttributes(typeof(TestAttribute), true).Any();
}
}
/// <summary>
/// Défine an aspect.
/// </summary>
public class MuCustomAspect : Aspect
{
public override IEnumerable<Advisor> Manage(MethodBase method)
{
//Aspect will advice method on boundary using MyCustomAdvice.
yield return Advice.For(method).Around(() => new MyCustomAdvice());
}
}
/// <summary>
/// Define an advice.
/// </summary>
public class MyCustomAdvice : IAdvice
{
public MyCustomAdvice()
{
}
public void Instance<T>(T value)
{
}
public void Argument<T>(ref T value)
{
}
public void Begin()
{
}
public void Await(MethodInfo method, Task task)
{
}
public void Await<T>(MethodInfo method, Task<T> task)
{
}
public void Continue()
{
}
public void Return()
{
}
public void Return<T>(ref T value)
{
}
public void Throw(ref Exception exception)
{
}
public void Throw<T>(ref Exception exception, ref T value)
{
}
public void Dispose()
{
}
}
}