2012-05-15 12 views
10

Estoy usando Ninject.Extensions.Factory con Ninject 3 para crear una fábrica, que crea diferentes tipos de IFoo según la cadena provista en la fábrica. Tengo una prueba de unidad de pasada, pero extrañamente, solo en el corredor de prueba Resharper. En el corredor de prueba NCrunch falla. ¿Es esto un problema de configuración de NCrunch, o necesito cambiar el código?Ninject ToFactory funciona en las pruebas de la unidad Resharper, pero no en NCrunch

La interfaz:

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

Los enlaces ninject:

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

La prueba:

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

Y la excepción 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) 

Respuesta

6

Aquí el código que funciona con 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()); 

ACTUALIZACIÓN

Esto funciona muy bien, y ordena a NCrunch. Sin embargo, Resharper se queja de que se ha cargado dos veces. La solución:

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

No voy a reclamar que es mejor, pero hasta ninject ofrece algo así como EnsureLoaded , una alternativa al #if (si desea un enfoque diferente) es comprobar si ya se ha cargado a través de Kernel.HasModule (typeof (FuncModule) .FullName) –

+0

Nos topamos con el mismo problema en un proyecto en el que extraemos dinámicamente todas las asambleas (incluso ninject) de recursos incrustados en el exe principal. Esta solución también funciona aquí (cargando manualmente 'FuncModule'). En nuestro caso, lo solucionamos con la solución de @JamesManning, ya que es un dll ya construido que se usa en varios lugares. –

4

El FuncModule no se carga cuando se ejecuta con ese TestRunner. Esto sucede en caso de que la extensión no se copie en el directorio de inicio del proceso ejecutado.

No hago NCrunch. Entonces no puedo decirte lo que está haciendo. Pero lo más probable es que copie los conjuntos de una manera diferente que el corredor de prueba R #. Puede cargar las extensiones manualmente, pero esto se siente como un truco.

8

Ir en la configuración NCrunch para la biblioteca de prueba de la unidad y establece Copiar ensamblados de referencia a espacio de trabajo a Verdadero.

NCrunch confuguration screenshot

+0

+1 Esta solución funcionó perfectamente para mí. No estoy seguro de si hay un gran impacto en el rendimiento o no. –

2

He estado usando la sugerencia de harriyott durante un año más o menos. Pero luego este problema pasó en nuestro TFS-Buildserver, también. Así que ahora evito que Ninject cargue automáticamente todas las extensiones y las carga manualmente. Esto evita la #if, #endif y el mismo código se ejecutará en ReSharper y NCrunch:

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

el resto es el mismo:

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()); 
Cuestiones relacionadas