Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock Microsoft.Office.Interop.Excel.Range with Moq?

I want to mock the Microsoft.Office.Interop.Excel.Range (and the other Microsoft.Office.Interop.Excel interfaces) to unit test my application. I'm using Moq 4.0.10827 with .NET 4 in C#.

In my unit test, I attempt to set up the behavior of the mock as follows:

        var range = new Mock<Microsoft.Office.Interop.Excel.Range>();
        range.Setup(r => r.get_Value(1)).Returns("Something");

        var classBeingTested = new MyClass(range.Object);

In the code being unit tested, I'm using the Range as follows:

    public MyClass(Range range)
    {
        var value = range[1].ToString();
    }

When the test runs, it produces the following exception:

        Error: Missing method 'instance object [My.Example.Implementation.MyClass] Microsoft.Office.Interop.Excel.Range::get__Default(object,object)' from class 'Castle.Proxies.RangeProxy'.

How can I implement this mocking successfully? I realize that isolating the Excel Interop functionality with a pattern such as https://stackoverflow.com/a/9486226/1548950 is a potential solution; however, I'd be happier with being able to create mocks from the Microsoft.Office.Interop.Excel interfaces.

EDIT: More details on this issue

OK, this is strange. I've created a project to test the suggestion by jimmy_keen. It works. However, when I use the same suggestion to test the project I had issues with, it throws the following exception:

Error: Missing method 'instance object [My.Example.Implementation.MyClass] Microsoft.Office.Interop.Excel.Range::get__Default(object,object)' from class 'Castle.Proxies.RangeProxy'.

Since jimmy_keen's suggestion worked fine on other projects, I started suspecting that there is something wrong with the project I'm testing the code with. So, I created a test solution that demonstrates the problem in detail: http://www7.zippyshare.com/v/70834394/file.html

The root of the problem seems to be that the project contains another class (that is not being unit tested) with essentially the following code:

using Microsoft.Office.Interop.Excel;
namespace Project
{
    public class UnTestedClass
    {
        public UnTestedClass(Worksheet sheet)
        {
            var foo = sheet.Range["Description"].Column;
        }
    }
}

I don't understand why this causes the issue, because I'm not using UnTestedClass in the unit test at all. Am I missing something in how I should use Moq, or have I stumbled upon a bug?

like image 732
Lauri Harpf Avatar asked Jul 24 '12 14:07

Lauri Harpf


1 Answers

Your code accesses indexer, and that's what you need to mock:

var range = new Mock<Microsoft.Office.Interop.Excel.Range>();
range.Setup(r => r[1, It.IsAny<object>()]).Returns("something");

Note that Range indexer actually takes two parameters - hence the It.IsAny<object>() constraint in call.

like image 156
k.m Avatar answered Oct 06 '22 00:10

k.m