Unplanned
Last Updated: 20 Jul 2020 09:41 by ADMIN
Surya
Created on: 02 Apr 2020 16:45
Type: Bug Report
4
Mocking constructor of COM interop types failed

Having the following COM interop class

[ClassInterface(ClassInterfaceType.None)]
[Guid("86332C4E-0BDE-46EC-94C5-0A946C33C682")]
[TypeLibType(TypeLibTypeFlags.FCanCreate)]
public class MyComObjectClass : IMyComObject, MyComObject
{
    public MyComObjectClass();

    [DispId(1)]
    public virtual string Echo(string message);
}

and the sample class that uses it:

public class MyComObjectClassProxy
{
    public string Echo(string message)
    {
        IMyComObject itf = null;
        try
        {
            itf = new MyComObjectClass();
            return itf.Echo(message);
        }
        finally
        {
            if (itf != null)
            {
                Marshal.ReleaseComObject(itf);
            }
        }
    }
}

When I try to call the arranged constructor I am getting an error "Cannot create instances of type requiring managed activation", the unit test code:

[TestMethod]
public void TestMethod1()
{
    var mock = Mock.Create<MyComObjectClass>();
    Mock.Arrange(() => new MyComObjectClass()).Returns(mock);

    var sut = new MyComObjectClassProxy();
    var actual = sut.Echo("Message");

    Assert.AreEqual(string.Empty, actual);
}
4 comments
ADMIN
Ivo
Posted on: 20 Jul 2020 09:41

Hello Gopi,

You are welcome! It would be nice to share whether the provided temporary solution is good enough for you.

Regards,
Ivo
Progress Telerik

Gopi
Posted on: 17 Jul 2020 11:02
Thank you. I will try this workaround.
ADMIN
Ivo
Posted on: 17 Jul 2020 09:38

Hello Gopi,

The issue is due to an attempt to modify the lifecycle of Runtime Callable Wrapper (RCW) by JustMock which is denied by CLR.

The good news is that there is a relatively easy workaround, it has just one drawback - requires some trivial changes in the test target code:

  • Create a private factory method that hides direct usage of new, for example:
static private MyComObjectClass CreateNewComObjectClassInstance()
{
    return new MyComObjectClass();
}
  • Modify the code where IMyComObject interface is retrieved:
public string Echo(string message)
{
    IMyComObject itf = null;
    try
    {
        itf = CreateNewComObjectClassInstance();
        return itf.Echo(message);
    }
    finally
    {
        if (itf != null)
        {
            Marshal.ReleaseComObject(itf);
        }
    }
}

This allows you to gain control over IMyComObject interface creation and could mock it by arranging a helper factory method. Find the sample code below:

[TestMethod]
public void TestNewComClassWithFactoryMockingSuceeded()
{
    var mock = Mock.Create<MyComObjectClass>();
    Mock.Arrange(() => mock.Echo(Arg.AnyString)).Returns(string.Empty);

    Mock.NonPublic.Arrange<IMyComObject>(typeof(ComClassProxy), "CreateNewComObjectClassInstance").Returns(mock);

    var sut = new ComClassProxy();
    var actual = sut.Echo("Message");

    Assert.AreEqual(string.Empty, actual);
}

I hope that the provided workaround is acceptable. If you have further questions or comments do not hesitate to write us back.

Regards,
Ivo
Progress Telerik

Gopi
Posted on: 17 Jul 2020 05:39
I am also facing the same problem. Can some one just a solution?