Как издеваться над классами ISerializable с помощью Moq?

Я совершенно новичок в Moq и теперь пытаюсь создать макет для класса System.Reflection.Assembly. Я использую этот код:

var mockAssembly = new Mock<Assembly>(); 
mockAssembly.Setup( x => x.GetTypes() ).Returns( new Type[] { 
    typeof( Type1 ), 
    typeof( Type2 ) 
} );

Но когда я запускаю тесты, я получаю следующее исключение:

System.ArgumentException : The type System.Reflection.Assembly 
implements ISerializable, but failed to provide a deserialization 
constructor 
Stack Trace: 
   at 
Castle.DynamicProxy.Generators.BaseProxyGenerator.VerifyIfBaseImplementsGet­ObjectData(Type 
baseType) 
   at 
Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode(Type[] 
interfaces, ProxyGenerationOptions options) 
   at Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxy(Type 
classToProxy, Type[] additionalInterfacesToProxy, 
ProxyGenerationOptions options) 
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type 
classToProxy, Type[] additionalInterfacesToProxy, 
ProxyGenerationOptions options, Object[] constructorArguments, 
IInterceptor[] interceptors) 
   at Moq.Proxy.CastleProxyFactory.CreateProxy[T](ICallInterceptor 
interceptor, Type[] interfaces, Object[] arguments) 
   at Moq.Mock`1.<InitializeInstance>b__0() 
   at Moq.PexProtector.Invoke(Action action) 
   at Moq.Mock`1.InitializeInstance() 
   at Moq.Mock`1.OnGetObject() 
   at Moq.Mock`1.get_Object() 

Не могли бы вы порекомендовать мне правильный способ издеваться над ISerializable классами (например, System.Reflection.Assembly) с помощью Moq.

Заранее спасибо!


person sam    schedule 23.04.2010    source источник


Ответы (5)


Проблема не в интерфейсе ISerializable. Вы можете имитировать классы ISerializable.

Обратите внимание на сообщение об исключении:

Тип System.Reflection.Assembly реализует ISerializable, но не может предоставить конструктор десериализации.

Проблема в том, что в сборке нет конструктора десериализации.

person Krzysztof Kozmic    schedule 23.04.2010
comment
Хорошо спасибо. Но не могли бы вы предложить, как в этом случае предоставить конструктор десериализации с использованием Moq. - person sam; 24.04.2010
comment
вы не можете - в сборке нет доступного конструктора, и поэтому он не может быть смоделирован при использовании Moq: | - person Krzysztof Kozmic; 24.04.2010
comment
Вам не нужно предоставлять конструктор десериализации для имитации сборки. Вы можете смоделировать класс взаимодействия _Assembly и при необходимости привести его к сборке. - person nathanchere; 10.07.2013

System.Reflection.Assembly является абстрактным, поэтому вы не можете создать его новый экземпляр. Однако вы можете создать тестовый класс, который делает это, и издевается над этим.

Пример:

[TestMethod]
public void TestSomethingThatNeedsAMockAssembly()
{
    string title = "title";
var mockAssembly = new Mock();
mockAssembly.Setup(a => a.GetCustomAttributes(It.Is(s => s == Type.GetType("System.Reflection.AssemblyTitleAttribute")), It.IsAny())).Returns(new System.Attribute[] { new AssemblyTitleAttribute(title) } );

var c = new ClassThatTakesAssemblyAndParsesIt(mockAssembly.Object); Assert.IsTrue(c.AssemblyTitle == title); //etc } public class TestAssembly : Assembly { public TestAssembly() { //could probably do something interesting here } }

person Chuck Rostance    schedule 10.09.2013
comment
+1 При использовании RhinoMocks трюк _Assembly у меня не сработал, и в итоге я использовал это. Просто искал вопрос, чтобы поделиться этими знаниями. - person mao47; 13.11.2013

Как уже объяснялось, проблема заключается в том, что Assembly не предоставляет конструктор десериализации. Хотя это не значит, что это невозможно сделать.

Решение с использованием Moq в соответствии с вашим примером:

    var mock = new Mock<_Assembly>();
    result.Setup(/* do whatever here as usual*/);

Обратите внимание, что для использования _Assembly вам потребуется ссылка на System.Runtime.InteropServices

person nathanchere    schedule 10.07.2013

Вместо макета вы можете попробовать создать динамическую сборку и построить ее.

var appDomain = AppDomain.CurrentDomain;
var assembly = appDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.ReflectionOnly);
person Michiel van Oosterhout    schedule 14.05.2010

Мне просто нужно было убедиться, что встроенный ресурс работает правильно; это сработало для моей ситуации:

    public class MockableAssembly : Assembly { }

    [TestClass]
    public class ApplicationSetupTests
    {
        [TestMethod]
        public void ApplyAsposeLicense_Success()
        {
            var mockAssembly = new Mock<MockableAssembly>();
            mockAssembly.Setup(a => a.GetManifestResourceStream(It.IsAny<string>())).Returns(mockedData);

            MethodIAmTesting(mockAssembly.Object);

            mockAssembly.Verify(a => a.GetManifestResourceStream("myString"), Times.Once);
        }
person John    schedule 06.03.2019
comment
Все, что мне было нужно, — это сборка, в которой я мог бы вызывать .GetTypes() с предсказуемыми типами, и это помогло мне исправить ситуацию. Как и этот ответ, создайте наследующий класс, например MockableAssembly. Моделируйте все функции, которые вам нужны, затем вы можете вернуть их к Assembly и снова поработать над ними. - person MickelsonMichael; 02.08.2019