How to mock ISerializable classes with Moq?
Asked Answered
S

5

6

I'm completly new to Moq and now trying to create a mock for System.Reflection.Assembly class. I'm using this code:

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

But when I run tests I get next exception:

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() 

Could you reccomend me the right way to mock ISerializable classes (like System.Reflection.Assembly) with Moq.

Thanks in advance!

Shallot answered 23/4, 2010 at 4:38 Comment(0)
H
2

The issue is not with ISerializable interface. You can mock ISerializable classes.

Notice the exception message:

The type System.Reflection.Assembly implements ISerializable, but failed to provide a deserialization constructor

Problem is, that Assembly does not provide deserialization constructor.

Howardhowarth answered 23/4, 2010 at 10:14 Comment(3)
Ok, thanks. But could you suggest how to provide deserialization constructor using Moq in that case.Shallot
you can't - Assembly does not have any accessible constructor, and as such it's unmockable when using Moq :|Howardhowarth
You don't need to provide a deserialization constructor to mock Assembly. You can mock the interop _Assembly class and cast to Assembly when needed.Dither
R
7

System.Reflection.Assembly is abstract, so you can't create a new instance of it. However, you could create a test class which does and Mock that.

Example:

[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 } }

Reflector answered 10/9, 2013 at 20:20 Comment(1)
+1 Using RhinoMocks, the _Assembly trick didn't work for me, and I ended up using this. Was just looking for a question to share this knowledge.Silt
D
3

As explained already, the problem is Assembly not exposing a deserialization constructor. This does not mean it can't be done though.

A solution using Moq as per your example would be:

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

Note that to use _Assembly you will need to reference System.Runtime.InteropServices

Dither answered 10/7, 2013 at 1:4 Comment(0)
H
2

The issue is not with ISerializable interface. You can mock ISerializable classes.

Notice the exception message:

The type System.Reflection.Assembly implements ISerializable, but failed to provide a deserialization constructor

Problem is, that Assembly does not provide deserialization constructor.

Howardhowarth answered 23/4, 2010 at 10:14 Comment(3)
Ok, thanks. But could you suggest how to provide deserialization constructor using Moq in that case.Shallot
you can't - Assembly does not have any accessible constructor, and as such it's unmockable when using Moq :|Howardhowarth
You don't need to provide a deserialization constructor to mock Assembly. You can mock the interop _Assembly class and cast to Assembly when needed.Dither
P
1

Instead of a mock you could try creating a dynamic assembly and build from that.

var appDomain = AppDomain.CurrentDomain;
var assembly = appDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.ReflectionOnly);
Pacifically answered 14/5, 2010 at 19:40 Comment(0)
G
1

I just needed to verify an embedded resource worked correctly; this worked for my situation:

    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);
        }
Geminian answered 6/3, 2019 at 14:33 Comment(1)
All I needed was an assembly I could call .GetTypes() on with predictable types, and this is what fixed it for me. Like this answer, create an inheriting class like MockableAssembly. Mock all the functions you need, then you can cast it back to Assembly and work on it againImpersonate

© 2022 - 2024 — McMap. All rights reserved.