2012-05-15 47 views
10

我使用Ninject.Extensions.Factory和Ninject 3創建工廠,該工廠根據提供給工廠的字符串創建不同類型的IFoo。我有一個通過單元測試,但奇怪的是,只有在Resharper測試運行。在NCrunch測試運行器中失敗。這是一個NCrunch配置問題,還是我需要更改代碼?Ninject ToFactory在Resharper單元測試中工作,但不是NCrunch

接口:

public interface IFooFactory 
{ 
    IFoo CreateFoo(string name); 
} 

的Ninject綁定:

kernel.Bind<IFooFactory>().ToFactory(() => new UseFirstParameterAsNameInstanceProvider()); 
kernel.Bind<IFoo>().To<BarFoo>().Named("Bar"); 

測試:

[Test] 
public void CanCreateFooTest() 
{ 
    var factory = (IFooFactory) Kernel.GetService(typeof(IFooFactory)); 
    var bar = factory.CreateFoo("Bar"); 
    Assert.AreEqual(typeof(BarFoo), bar.GetType()); 
} 

而且NCrunch例外:

System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation. 
    ----> Ninject.ActivationException : Error activating IInterceptor using conditional implicit self-binding of IInterceptor 
Provider returned null. 
Activation path: 
    2) Injection of dependency IInterceptor into parameter of constructor of type IFooFactoryProxy 
    1) Request for IFooFactory 

Suggestions: 
    1) Ensure that the provider handles creation requests properly. 

    at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner) 
    at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner) 
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) 
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
    at Ninject.Infrastructure.Language.ExtensionsForIEnumerable.ToArraySlow(IEnumerable series, Type elementType) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerable.cs:line 29 
    at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 149 
    at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 114 
    at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96 
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() 
    at System.Linq.Buffer`1..ctor(IEnumerable`1 source) 
    at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source) 
    at Ninject.Activation.Providers.StandardProvider.Create(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 95 
    at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:line 157 
    at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 386 
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() 
    at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source) 
    at Ninject.KernelBase.System.IServiceProvider.GetService(Type service) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 553 
    at FooProject.Tests.CanCreateFooTest() in C:\Projects\FooProject ... 
--ActivationException 
    at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:line 165 
    at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 386 
    at System.Linq.Enumerable.WhereSelectListIterator`2.MoveNext() 
    at System.Linq.Enumerable.<CastIterator>d__b1`1.MoveNext() 
    at System.Linq.Buffer`1..ctor(IEnumerable`1 source) 
    at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source) 

回答

6

這裏與NCrunch工作代碼:

 var kernel = new StandardKernel(); 
     kernel.Bind<IFooFactory>().ToFactory(() => new UseFirstParameterAsNameInstanceProvider()); 
     kernel.Bind<IFoo>().To<BarFoo>().Named("Bar"); 
     kernel.Load<FuncModule>(); 

     var factory = kernel.Get<IFooFactory>(); 
     var bar = factory.CreateFoo("Bar"); 
     Assert.Equal(typeof(BarFoo), bar.GetType()); 

UPDATE

這個偉大的工程,並挑選出NCrunch。但是,Resharper抱怨說它已經加載了兩次。解決方法:

#if NCRUNCH 
     Kernel.Load<FuncModule>(); 
    #endif 
+3

我不會要求它的好,但直到NInject提供類似EnsureLoaded ,#if的替代方法(如果你想要一種不同的方法)正在檢查它是否已經通過Kernel.HasModule(typeof(FuncModule).FullName)加載了。 –

+0

我們在一個項目中遇到同樣的問題,我們動態地提取所有程序集(包括ninject)來自主要exe中的嵌入式資源。這個解決方案也可以在這裏工作(手動加載'FuncModule')。在我們的例子中,我們用@ JamesManning的解決方案修復了它,因爲它已經在幾個地方使用過了。 –

4

與該TestRunner一起運行時,FuncModule未加載。如果擴展未被複制到已執行進程的啓動目錄,則會發生這種情況。

我不會NCrunch。所以我不能告訴你它在做什麼。但很可能它以與R#測試運行器不同的方式複製程序集。你可以手動加載擴展,但這感覺像一個黑客。

8

轉到成用於單元測試庫中的NCrunch配置,並設置複製引用的程序到工作區

NCrunch confuguration screenshot

+0

+1此解決方案對我來說非常合適。不確定是否會有很大的性能影響。 –

2

我一直在使用harriyott的建議一年左右。但是這個問題也發生在我們的TFS-Buildserver上。所以現在我避免Ninject自動加載所有擴展並手動加載它們。這就避免了#if#endif和相同的代碼將在ReSharper的和NCrunch運行:

var kernel = new StandardKernel(new NinjectSettings { LoadExtensions = false}); 
kernel.Load<FuncModule>(); 

其餘不變:

kernel.Bind<IFooFactory>().ToFactory(() => new UseFirstParameterAsNameInstanceProvider()); 
kernel.Bind<IFoo>().To<BarFoo>().Named("Bar"); 

var factory = kernel.Get<IFooFactory>(); 
var bar = factory.CreateFoo("Bar"); 
Assert.Equal(typeof(BarFoo), bar.GetType());