TypeLoadException при попытке издеваться над IObjectSet с помощью Moq
-
14-11-2019 - |
Вопрос
У меня есть следующий код установки:
MockOf<IObjectSet<Dummy>>().Setup(c => c.AddObject(dummy)).Verifiable();
MockOf<IObjectContextWrapper>().Setup(c => c.GetObjectSet<Dummy>()).Returns(MockOf<IObjectSet<Dummy>>().Object);
где Dummy
является пустым определением класса, и dummy
это Dummy
. MockOf<T>()
— это функция управления макетом в базовом классе, которая по сути гарантирует, что каждый раз, когда она вызывается для типа, возвращается один и тот же макетный экземпляр.
Тест, содержащий этот код установки, завершается неудачей с TypeLoadException
и следующее сообщение:
System.TypeLoadException:Введите «IObjectSet`1Proxy389e220f10aa4d9281d0b9e136edc1d4» из сборки «DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=a621a9e7e5c32e69» пытается реализовать недоступный интерфейс.
в System.Reflection.Emit.TypeBuilder.TermCreateClass (модуль RuntimeModule, Int32 tk, тип ObjectHandleOnStack)
в System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
в System.Reflection.Emit.TypeBuilder.CreateType()
в Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
в Castle.DynamicProxy.Generators.InterfaceProxyWithTargetGenerator.GenerateCode (интерфейсы типа proxyTargetType, типа [], параметры ProxyGenerationOptions)
в Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget (Type InterfaceToProxy, Type[] extraInterfacesToProxy, параметры ProxyGenerationOptions, перехватчики IInterceptor[])
в Moq.Mock1.<InitializeInstance>b__0()
1.ИнициализироватьЭкземпляр()
at Moq.Mock
в Moq.Mock`1.get_Object()
в OddEnds.Tests.Data.EntityFramework.RepositoryTest.Delete_DeletesObjectFromObjectSet() в RepositoryTest.cs:строка 43
я импортировал System.Data.Objects
и ссылался как на System.Data.Entity.dll, так и на Microsoft.Data.Entity.CTP.dll как в тестовом проекте, так и в проекте, в котором находится тестируемый класс.Сборка завершается успешно без ошибок, предупреждений или сообщений (за исключением нескольких, связанных с контрактами кода...).
Как это исправить?
Решение
Являются ли какие-либо интерфейсы или классы, которые вы используете в своих тестах, внутренними?Вы используете что-то вроде [assembly: InternalsVisibleTo("YourTestAssembly")]
чтобы заставить вещи скомпилироваться?
Если да, вам также потребуется добавить его для DynamicProxyGenAssembly2, чтобы Moq динамически создавал прокси для классов.
//goes in the AssemblyInfo.cs where the internal interfaces / classes are defined
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
Вот соответствующий пост на эту тему
http://sonofpirate.blogspot.com/2009/09/my-first-foray-into-unit-testing-with.html
надеюсь, это поможет
Другие советы
Я обнаружил, что в моем случае я создал экземпляр класса Dummy для использования в моем модульном тесте, который оказался частным (поскольку на самом деле я не хотел делиться тестовым объектом снаружи).
Мой код был примерно таким:
var mockMonitor = new Mock<ICacheMonitor<int, PrivateObject>>();
где PrivateObject был определением частного класса в моем TestClass.Таким образом, исправление в моем случае заключается в том, чтобы гарантировать, что любой из типов в вашем конструкторе Mock является общедоступным.
public class PrivateObject () {}
(Очевидно, я бы также не назвал свой публичный объект PrivateObject...)
Я наткнулся на другой случай, который сначала не мог понять.Я работал над прокси-сервером для интерфейса, созданного внутри моего модульного теста...
public IDoWork
{
void DoWork();
}
Мне потребовалась целая вечность, чтобы понять, что проблема была не в этом интерфейсе, а в том, что сам модульный тест не был общедоступным:
class TestSomething // missing public keyword
{
// .. some test which tries to create a mock of the interface
public IDoWork
{
void DoWork();
}
}
Итак, хотя IDoWork говорит, что он общедоступен, на самом деле это не так, поскольку он заключен в частный класс.
Надеюсь, это кому-то поможет.