Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mock.Of of Excel interop classes fails to initialize #1072

Closed
killergege opened this issue Oct 13, 2020 · 5 comments · Fixed by #1076
Closed

Mock.Of of Excel interop classes fails to initialize #1072

killergege opened this issue Oct 13, 2020 · 5 comments · Fixed by #1076
Labels
Milestone

Comments

@killergege
Copy link

I have a project that has a lot of tests on Excel interop classes.
Those were working fine with my current test project (net452, Moq 4.8, Microsoft.Office.Interop.Excel v12.0.4518.1014, NUnit v3.12...)

But after upgrading to Moq 4.14 & Microsoft.Office.Interop.Excel v15.0.4795.1000, all the Mock.Of on interop classes fail to initialize.
I had other setup issues following interop upgrade (because they stated to use dynamic in some places, instead of object) but it seems that this is a different problem.

[Test]
public void Test_Works()
{
                var worksheet = new Mock<Worksheet>();
                var parent = new Mock<Workbook>();
                parent.Setup(x => x.FullName).Returns(string.Empty);
                worksheet.Setup(x => x.Parent).Returns(parent.Object);
}

[Test]
public void Test_Fails()
{
                var worksheet = new Mock<Worksheet>();
                var v = Mock.Of<Workbook>(x => x.FullName == string.Empty);
                worksheet.Setup(x => x.Parent).Returns(v);
}

The error is different based on the Moq version, but they all fail :

Moq v4.13.1

  Message:
    System.ArgumentException : Method 'Moq.Language.Flow.IReturnsResult`1[Microsoft.Office.Interop.Excel.Workbook] Returns(System.String)' declared on type 'Moq.Language.IReturns`2[Microsoft.Office.Interop.Excel.Workbook,System.String]' cannot be called with instance of type 'Moq.Mock`1[System.String]'
  Stack Trace:
    Expression.ValidateCallInstanceType(Type instanceType, MethodInfo method)
    Expression.ValidateStaticOrInstanceMethod(Expression instance, MethodInfo method)
    Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
    MockSetupsBuilder.ConvertToSetup(Expression targetObject, Expression left, Expression right)
    MockSetupsBuilder.ConvertToSetupProperty(Expression targetObject, Expression left, Expression right)
    MockSetupsBuilder.ConvertToSetup(Expression left, Expression right)
    MockSetupsBuilder.VisitBinary(BinaryExpression node)
    BinaryExpression.Accept(ExpressionVisitor visitor)
    ExpressionVisitor.Visit(Expression node)
    ExpressionVisitor.VisitLambda[T](Expression`1 node)
    Expression`1.Accept(ExpressionVisitor visitor)
    ExpressionVisitor.Visit(Expression node)
    ExpressionVisitor.VisitUnary(UnaryExpression node)
    MockSetupsBuilder.VisitUnary(UnaryExpression node)
    UnaryExpression.Accept(ExpressionVisitor visitor)
    ExpressionVisitor.Visit(Expression node)
    ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
    ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
    MockSetupsBuilder.VisitMethodCall(MethodCallExpression node)
    MethodCallExpression.Accept(ExpressionVisitor visitor)
    ExpressionVisitor.Visit(Expression node)
    MockQueryable`1.Execute[TResult](Expression expression)
    Queryable.First[TSource](IQueryable`1 source, Expression`1 predicate)
    Mock.Of[T](Expression`1 predicate, MockBehavior behavior)
    Mock.Of[T](Expression`1 predicate)
    UnitTest1.Test_Fails() line 22

Moq v4.14.6

  Message:
    System.ArgumentException : Object instance was not created by Moq.
    Parameter name: mocked
  Stack Trace:
    Mock.Get[T](T mocked)
    lambda_method(Closure , Workbook )
    Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
    lambda_method(Closure )
    EnumerableExecutor`1.Execute()
    IQueryProvider.Execute[S](Expression expression)
    Queryable.First[TSource](IQueryable`1 source, Expression`1 predicate)
    lambda_method(Closure )
    MockQueryable`1.Execute[TResult](Expression expression)
    Queryable.First[TSource](IQueryable`1 source, Expression`1 predicate)
    Mock.Of[T](Expression`1 predicate, MockBehavior behavior)
    Mock.Of[T](Expression`1 predicate)
    UnitTest1.Test_Fails() line 22

Is it expected?
Do you have a workaround ?
Replacing all the Mock.Of<>() by new Mock<>() + setup is a lot of work and adds a lot of "useless" rows...

@stakx
Copy link
Contributor

stakx commented Oct 13, 2020

But after upgrading to Moq 4.14 & Microsoft.Office.Interop.Excel v15.0.4795.1000

@killergege, can you tell which of the two updates causes the issue? That must be due to the interop update, because I can reproduce the problem you're seeing with all versions of Moq, going all the way back to 4.0.0. I cannot currently offer a workaround other than the one you're already aware of—using new Mock<T> instead—but let's keep that around as something we should fix.

Unfortunately I don't have a copy of the Excel v12 type library available. Could you possibly provide an assembly containing the above two tests, compiled against the old versions where everything passed? If you could ensure that the COM interfaces get embedded in the assembly, that would allow me to investigate what changes in the type libraries make Moq fail.

@killergege
Copy link
Author

We are using the nuget package to get the interop objects : https://www.nuget.org/packages/microsoft.office.interop.excel/
Our build server don't have Excel so I guess this is enough. If not I'll try to get you what you asked but in my corporate network this is not easy to send files outside :).

@stakx
Copy link
Contributor

stakx commented Oct 13, 2020

Ah, excellent! I wasn't aware of that NuGet package. Thank you for pointing me towards it... that should indeed be sufficient.

@stakx
Copy link
Contributor

stakx commented Oct 13, 2020

@killergege, I've compared the Excel COM interop libraries. They appear to differ in (among other things) the presence or absence of [CompilerGenerated] custom attributes on the Workbook and related types, and it appears to be the presence of that attribute that causes stuff inside Moq to go wrong:

Moq queries for this attribute in some places to recognize captured variables and anonymous types (those can show up in LINQ queries that use query comprehension syntax). In the current version, Moq erroneously enters into this "then" clause when it shouldn't... and that's what makes your code fail.

Not yet sure how to fix this properly, but at least a fix is possible. A very crude fix would consist of adding an && !pe.Type.IsImport check in the line of code referenced above... but that would be hardly pretty. I'll try to come up with something better.

@stakx
Copy link
Contributor

stakx commented Oct 13, 2020

@killergege, since previous versions of Moq failed with different error messages, I can't completely rule out other causes for failure in a real-world use case. If problems with mocking Workbook still occur after upgrading Moq to the upcoming version, please post again here, and we'll reopen this issue.

@stakx stakx modified the milestones: 4.15.0, 4.14.7 Oct 14, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants