问题
So, using NUnit and RhinoMocks:
//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>();
...
The error I get is:
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
When attempting to generate the mock against the concrete class, I get a similar error, this time on the QueryFor() method. If I attempt to redefine the methods that use TRest in the ISecurityRepository interface, I get a "System.BadImageFormatException : An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)" which looks like a step backwards.
I think the core problem is that RhinoMocks is getting confused by the generic parameters being used as generic type restrictions. I have no clue exactly where it's being confused and therefore I don't know how or if I can unconfuse it. I have adequate integration test coverage that I could ignore these failing unit tests if I absolutely have to, but obviously I'd rather fix them if I can. Your thoughts?
回答1:
It looks like this is a known issue caused by Castle.DynamicProxy
that is fixed in the latest trunk of that project, but still broken in the latest Rhino Mocks release:
http://groups.google.com/group/rhinomocks/browse_thread/thread/2c1b53bf66b77b8e/ad09a6cd1e304a93
If you're feeling adventurous you can build your own Rhino Mocks with the latest DynamicProxy and it should be fixed.
回答2:
Looks like Castle Dynamic Proxy (which Rhino Mocks uses for proxy generation) is not generating the proxy class correctly given the way that you've defined your generic arguments. You can generate a proxy (and hence a mock) if you define your IRepository like this instead:
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);
}
If you really need it defined the other way, you'll have to file a bug with Rhino Mocks.
来源:https://stackoverflow.com/questions/4382624/cant-get-rhinomocks-to-emit-a-mock-that-follows-the-generic-type-restriction-ru