我在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项目中工作,而不是在单元测试项目中。
答案 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>();
}
}