在单元测试中使用PostSharp

时间:2015-03-19 09:24:01

标签: c# unit-testing postsharp vs-unit-testing-framework

我在ASP.NET MVC项目中使用PostSharp MethodInteceptionAspect。它工作正常,但我想在单元测试中测试我的方面。当我在单元测试中向任何方法添加一个方面时,它编译正常,但它在运行时失败并显示以下消息:

Unable to create instance of class PNAF.Tests.Auth.DatabaseSessionScopeAspectTests. Error: System.TypeInitializationException: The type initializer for 'PostSharp.ImplementationDetails_e613b708.<>z__a_1' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object..
    at PNAF.Core.IoC.ServiceLocator.Resolve() in ServiceLocator.cs: line 17
   at PNAF.Modules.Auth.Aspects.DatabaseSessionScopeAttribute.RuntimeInitialize(MethodBase method) in DatabaseSessionScopeAttribute.cs: line 24
   at PostSharp.ImplementationDetails_e613b708.<>z__a_1..cctor() in :line 0
 --- End of inner exception stack trace ---
    at PostSharp.ImplementationDetails_e613b708.<>z__a_1.Initialize()
   at PNAF.Tests.Auth.DatabaseSessionScopeAspectTests..cctor() in :line 0

编译应用了postharp方面(我已经检查了编译的MSIL)但是在运行时我不能创建具有截获方法的类的实例。

仅在运行测试时才会发生这种情况。 ASP.NET MVC项目中的拦截很好。

使用PostSharp方面的单元测试示例:

[TestClass]
public class DatabaseSessionScopeAspectTests : TestBase
{
    [TestMethod]
    public void DataSessionScopeTest()
    {
        var data = GetData();
        Assert.IsNotNull(data);
    }

    [DatabaseSessionScope] // this is PostSharp MethodInterceptionAspect
    private IList<User> GetData()
    {
        // some code
    }
}

顺便说一句:我正在使用VS单元测试框架。


修改

我发现当我删除某个方面的私有财产时,它会起作用。

方面看起来像这样:

public class DatabaseSessionScopeAttribute : MethodInterceptionAspect
{
    private IDatabaseSessionProvider databaseSessionProvider;

    public override void RuntimeInitialize(MethodBase method)
    {
        base.RuntimeInitialize(method);
        databaseSessionProvider = ServiceLocator.Resolve<IDatabaseSessionProvider>();
    }

    public override void OnInvoke(MethodInterceptionArgs args)
    {
        // some code
    }
}

当我删除IDatabaseSessionProvider时,它可以正常工作。

任何人都可以解释为什么这是必要的吗?我不能理解为什么它在Web项目中工作,而不是在单元测试项目中。

1 个答案:

答案 0 :(得分:1)

似乎在初始化IoC容器之前调用了RuntimeInitialize。最简单的解决方案可能是延迟初始化databaseSessionProvider。除此之外,databaseSessionProvider字段应标记为NonSerializable

编辑:根据马丁的反对意见确定的例子

[Serializable]
public class DatabaseSessionScopeAttribute : MethodInterceptionAspect
{
    [NonSerialized]
    private Lazy<IDatabaseSessionProvider> databaseSessionProvider;

    public override void RuntimeInitialize(MethodBase method)
    {
        base.RuntimeInitialize(method);
        databaseSessionProvider = 
            new Lazy<IDatabaseSessionProvider>(SomeSessionProviderFactoryMethod);
    }

    private static IDatabaseSessionProvider SomeSessionProviderFactoryMethod()
    {
        return ServiceLocator.Resolve<IDatabaseSessionProvider>();
    }
}