如何在单元测试中调用Postsharp Aspect?

How to call Postsharp Aspect in Unit Test?

我有一个方面排序列表。

public override void OnInvoke(MethodInterceptionArgs args)
{
    args.Proceed();
    var string_list = (args.ReturnValue as List<string>);
    string_list.Sort();

    Console.WriteLine("Postsharp Aspect içerisinde sıralanan koleksiyon: ");
    foreach (var item in string_list)
    {
      Console.WriteLine(item);
    }
}

我有一个返回列表的方法。

    [PostSharpExecuteAfterMethod]
    public virtual List<string> Liste_Döndür()
    {
        List<string> liste = new List<string>();
        liste.Add("g");
        liste.Add("b");
        liste.Add("hjh");
        liste.Add("a");

        Console.WriteLine("Method'dan dönen string liste: ");
        foreach (var item in liste)
        {
            Console.WriteLine(item);
        }

        return liste;
    }

这是我的测试方法。

  public class SomeClass
  {
    [PostSharpExecuteAfterMethod]
    public virtual List<string> GimmeSomeData()
    {
        throw new NotImplementedException();
    }
  }

[TestClass]
public class UnitTest1
{
    [TestMethod]
    //[PostSharpExecuteAfterMethod]
    public void TestMethod1()
    {
        var mock = new Mock<SomeClass>();
        mock.Setup(m => m.GimmeSomeData()).Returns(() => new List<string> { "1", "2", "3" });
        //liste
        var resultList = mock.Object.GimmeSomeData();
    }
}

所以,我想使用 Moq 在我的测试方法中调用我的方面。每当我尝试创建一个模拟的 class 之类的东西时。它没有用。我怎样才能做到这一点?

由于目标方法上拦截的顺序,您的代码示例中的方面未被调用。模拟拦截器添加在 PostSharp 拦截器之前,因此它 returns PostSharp 方面有机会执行之前的结果。

在大多数情况下,这是所需的行为。您可以将方面视为方法中的附加代码。因此,您自己的代码和应用方面应作为一个单元进行测试。

如果您的用例要求您在测试期间将方面和原始方法体分开,那么您需要确保在 PostSharp 方面之后调用模拟拦截器。您可以在下面找到一个示例 MockAspect 来实现这一点:

public interface IMockable<T> where T : class
{
    Mock<T> CreateMock();
}

[Conditional( "DEBUG" )] // Exclude mocking interceptor in release builds.
public class MockAspect : TypeLevelAspect, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
    {
        Type targetType = (Type) targetElement;
        yield return new AspectInstance( targetElement, (IAspect) Activator.CreateInstance( typeof( MockAspectImpl<> ).MakeGenericType( targetType ) ) );
    }
}

[PSerializable]
// Make sure we are ordered after our aspect PostSharpExecuteAfterMethod.
[AspectTypeDependency(AspectDependencyAction.Order, AspectDependencyPosition.After, typeof( PostSharpExecuteAfterMethod ))]
public class MockAspectImpl<T> : IInstanceScopedAspect, IAdviceProvider, IMockable<T> where T : class
{
    [PNonSerialized]
    private Mock<T> mock;

    public object CreateInstance( AdviceArgs adviceArgs )
    {
        return new MockAspectImpl<T>();
    }

    public void RuntimeInitializeInstance()
    {
    }

    public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
    {
        yield return new IntroduceInterfaceAdviceInstance( typeof( IMockable<T> ) );
    }

    Mock<T> IMockable<T>.CreateMock()
    {
        this.mock = new Mock<T>();
        return this.mock;
    }

    [OnMethodInvokeAdvice]
    [MulticastPointcut( Targets = MulticastTargets.Method,
                        Attributes = MulticastAttributes.Instance | MulticastAttributes.Public | MulticastAttributes.Virtual )]
    public void OnMethodInvoke( MethodInterceptionArgs args )
    {
        if ( this.mock != null )
        {
            args.ReturnValue = args.Method.Invoke( mock.Object, args.Arguments.ToArray() );
        }
        else
        {
            args.Proceed();
        }
    }
}

接下来您可以将 MockAspect 应用于您的目标 class:

[MockAspect]
public class SomeClass
{
    [PostSharpExecuteAfterMethod]
    public virtual List<string> GimmeSomeData()
    {
        throw new NotImplementedException();
    }
}

这就是您如何使用在方面之后调用的模拟:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var obj = new SomeClass();
        var mock = ( (IMockable<SomeClass>) obj ).CreateMock();
        mock.Setup( m => m.GimmeSomeData() ).Returns( () => new List<string> { "3", "1", "2" } );

        var resultList = obj.GimmeSomeData();

        Console.WriteLine( "Result: {0}", string.Join( ", ", resultList ) );
    }
}