2015-03-19 126 views
0

我在ASP.NET MVC項目中使用PostSharp MethodInteceptionAspect。它工作正常,但我想在單元測試中測試我的方面。當我在單元測試添加一個方面的任何方法將其編譯確定,但它在運行時失敗,此消息:在單元測試中使用PostSharp

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 

編譯應用postsharp方面(我已經檢查了編譯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項目中工作,但不在單元測試項目中。

+2

由於這是一個數據庫會話scope屬性是缺少在單元測試項目中的配置設置固定的嗎?例如一個數據庫連接字符串? – 2015-03-19 09:25:49

+0

不,當我在方法本身中刪除方面並創建數據庫會話時,它可以工作。即使我不僅僅因爲類包含一個方面而調用方法,它也會以這種方式失敗。 – 2015-03-19 09:34:51

回答

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>(); 
    } 
} 
+0

是的,這可能是原因。你的代碼稍作修改後就可以工作我不得不將懶惰字段的國際化放到'RuntimeInitialize()'方法中,因爲不調用方面構造函數。如果您編輯答案,我會將其標記爲已接受的答案。 – 2015-03-19 13:19:29

+0

是的,你是絕對正確的。答案固定。感謝您指出。 – 2015-03-20 09:25:11