2010-12-07 14 views
5

Así, utilizando NUnit y RhinoMocks:No se puede obtener RhinoMocks para emitir una maqueta que sigue a la restricción de tipo genérico reglas

//Defines basic behavior of all persistable domain objects 
public interface IDomainObject {...} 

//defines domain objects specific to the Security DB 
public interface ISecurityDomainObject : IDomainObject {...} 

//Defines a basic transactional data Repository; there are multiple implementors 
//which each close TRest to the interface that defines their DB's domain classes 
public interface IRepository<TRest> : IDisposable where TRest:IDomainObject 
{ 
    IUnitOfWork BeginUnitOfWork(); 
    void CommitUnitOfWork(IUnitOfWork unitOfWork); 
    void RollBackUnitOfWork(IUnitOfWork unitOfWork);   
    void Save<T>(T domainObject, IUnitOfWork unitOfWork) where T : class, TRest;   
    IQueryable<T> QueryFor<T>(IUnitOfWork unitOfWork) where T :class, TRest; 
} 

public interface ISecurityRepository:IRepository<ISecurityDomainObject> {} 

public class SecurityRepository:ISecurityRepository 

... 

//This line breaks when run in an NUnit test 
var securityRepository = MockRepository.GenerateMock<ISecurityRepository>(); 
... 

El error que consigo es:

System.TypeLoadException : Method 'Save' on type 'ISecurityRepositoryProxyb8e21deb3cb04067a01ac5b63f7045af' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' tried to implicitly implement an interface method with weaker type parameter constraints. 
at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type) 
at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock() 
at System.Reflection.Emit.TypeBuilder.CreateType() 
at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType() 
at Castle.DynamicProxy.Generators.InterfaceProxyWithTargetGenerator.GenerateCode(Type proxyTargetType, Type[] interfaces, ProxyGenerationOptions options) 
at Castle.DynamicProxy.DefaultProxyBuilder.CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) 
at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) 
at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, IInterceptor[] interceptors) 
at Rhino.Mocks.MockRepository.MockInterface(CreateMockState mockStateFactory, Type type, Type[] extras) 
at Rhino.Mocks.MockRepository.CreateMockObject(Type type, CreateMockState factory, Type[] extras, Object[] argumentsForConstructor) 
at Rhino.Mocks.MockRepository.DynamicMock(Object[] argumentsForConstructor) 
at Rhino.Mocks.MockRepository.<>c__DisplayClass7`1.<GenerateMock>b__6(MockRepository r) 
at Rhino.Mocks.MockRepository.CreateMockInReplay(Func`2 createMock) 
at Rhino.Mocks.MockRepository.GenerateMock(Object[] argumentsForConstructor) 
at CSHD.Tests.Unit.Presentation.LoginTests.TestAuthenticationFails() in LoginTests.cs: line 138 

Al intentar generar el simulacro en contra de la clase concreta, obtengo un error similar, esta vez en el método QueryFor(). Si intento redefinir los métodos que usan TRest en la interfaz ISecurityRepository, aparece una "System.BadImageFormatException: se intentó cargar un programa con un formato incorrecto. (Excepción de HRESULT: 0x8007000B)" que parece un paso atrás .

Creo que el problema principal es que RhinoMocks se confunde con los parámetros genéricos que se utilizan como restricciones de tipo genérico. No tengo ni idea de dónde se confunde y, por lo tanto, no sé cómo o si puedo desconfundirlo. Tengo una cobertura de prueba de integración adecuada que podría ignorar estas pruebas de unidades fallidas si es absolutamente necesario, pero obviamente prefiero corregirlas si puedo. ¿Tus pensamientos?

Respuesta

6

Parece que este es un problema conocido causado por Castle.DynamicProxy que se corrige en el último tronco de ese proyecto, pero aún roto en la última versión burla de Rhino:

http://groups.google.com/group/rhinomocks/browse_thread/thread/2c1b53bf66b77b8e/ad09a6cd1e304a93

Si se siente Aventurero puede construir sus propios Rhino Mocks con el último DynamicProxy y debería ser reparado.

+0

Gracias. Creo que simplemente ignoraré la prueba por el momento, y estaré atento a la próxima versión de Rhino Mocks. Mientras se arregle a partir del próximo lanzamiento, no me siento tan mal por hacerlo. – KeithS

+0

Solo para confirmar la sugerencia de Ergwun, tuve el mismo problema. Revisé la fuente de Rhino y lo actualicé todo en la versión troncal de Castle, y el error está corregido. – FinnNk

1

Parece que Castle Dynamic Proxy (que Rhino Mocks usa para la generación de proxy) no está generando la clase de proxy correctamente dado la forma en que ha definido sus argumentos genéricos. Puede generar un proxy (y por lo tanto una maqueta) si define su IRepository esta forma:

public interface IRepository<T> : IDisposable where T : class, IDomainObject 
{ 
    IUnitOfWork BeginUnitOfWork(); 
    void CommitUnitOfWork(IUnitOfWork unitOfWork); 
    void RollBackUnitOfWork(IUnitOfWork unitOfWork);   
    void Save(T domainObject, IUnitOfWork unitOfWork);   
    IQueryable<T> QueryFor(IUnitOfWork unitOfWork); 
} 

Si realmente necesita que define la otra manera, usted tiene que presentar un error con burla de Rhino.

+0

Realmente necesito que se defina de la manera en que lo tengo. Tengo varias implementaciones de IRepository que funcionan con un DB diferente (no inventé el esquema, lo heredé) y cada implementación funciona con un subconjunto diferente del dominio. La definición que tengo asegura en tiempo de compilación que el código no puede intentar solicitar que un Repositorio trabaje con un objeto que no es parte de su esquema. Lo que tienes allí básicamente requeriría un repositorio por objeto de dominio, ya que T no se puede definir como ISecurityDomainObject porque Save y QueryFor no podrían saber el tipo concreto (que necesitan). – KeithS

+0

Bastante justo. El problema es que la excepción no está ocurriendo en Rhino Mocks, sino en Castle DynamicProxy. Comprobé Moq (que usa una versión más reciente de Castle DynamicProxy que Rhino MOCKS) y también sufre de esta limitación. Por el momento, esta interfaz no se puede burlar usando Rhino Mocks o Moq. Para que esto se solucione, Castle DynamicProxy tendrá que solucionar el problema subyacente. Desearía tener una mejor respuesta para ti. –

Cuestiones relacionadas