Не удается заставить RhinoMocks создавать макет, который следует общим правилам ограничения типов - PullRequest
5 голосов
/ 08 декабря 2010

Итак, используя NUnit и 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>();
...

Я получаю ошибку:

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 

При попытке создать макет для конкретного класса я получаю похожую ошибкуна этот раз для метода QueryFor ().Если я пытаюсь переопределить методы, которые используют TRest в интерфейсе ISecurityRepository, я получаю «System.BadImageFormatException: была сделана попытка загрузить программу с неверным форматом. (Исключение из HRESULT: 0x8007000B)», которая выглядит как шаг назад.

Я думаю, что основная проблема в том, что RhinoMocks смущается общими параметрами, используемыми в качестве ограничений универсального типа.Я понятия не имею, где именно это происходит, и поэтому я не знаю, как и смогу ли я это объяснить.У меня есть достаточный охват интеграционных тестов, что я могу игнорировать эти провальные модульные тесты, если мне это абсолютно необходимо, но, очевидно, я бы лучше их починил, если смогу.Ваши мысли?

Ответы [ 2 ]

6 голосов
/ 08 декабря 2010

Похоже, это известная проблема, вызванная Castle.DynamicProxy, которая исправлена ​​в последней стволе этого проекта, но все еще не устранена в последнем выпуске Rhino Mocks:

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

Если вы любите приключения, вы можете создавать собственные Rhino Mocks с последней версией DynamicProxy, и это должно быть исправлено.

1 голос
/ 08 декабря 2010

Похоже, что Castle Dynamic Proxy (который Rhino Mocks использует для генерации прокси) неправильно генерирует прокси-класс, учитывая то, как вы определили свои общие аргументы. Вы можете сгенерировать прокси (и, следовательно, макет), если вместо этого определите свой IRepository:

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);
}

Если вам действительно нужно, чтобы оно было определено иначе, вам придется отправить сообщение об ошибке в Rhino Mocks.

...