Mocked object doesn't have all properties shown in Intellisense - in one project but has them in the other

前端 未结 4 1987
既然无缘
既然无缘 2021-01-16 03:24

I\'m mocking VSTO objects and in one project (I didn\'t write) it has this code:

var listOfSheets = new List();
var mockSheets = Substitute.         


        
相关标签:
4条回答
  • 2021-01-16 03:32

    Sounds like the following may be the cause:

    VSTO Specific Project to be tested (Addin/taskpane/etc)
    VSTO ver: VSTO 3.0 SP1
    .NET ver: .NET 3.5 SP1

    VS 2010 Test project for project above
    defaults to
    .NET Ver: .NET 4.0

    This would create a referencing problem when going to mock up the objects as the test project is expecting to be able to use MS.Csharp (i guess) and possibly other references.

    So the exception is not really refering to the Null value returned by the mock object at all, but rather a null binding exception caused by not being able to load .NET 4.0's CSharp library.

    Therefore as you discovered the solution is to remove .net 4.0 Csharp reference. It is perhaps unnecessary although to set the project to run under .net 3.5? Not sure you would have to test if any other problems occur. But I guess better to keep test projects on .net 4 if you can. Unless someone can indicate if this is not best practise.

    0 讨论(0)
  • 2021-01-16 03:45

    This is a wild guess, but Office Interop arrays are 1 based, not 0 based. I havent looked into it but this may be defined in the metadata. Try this:

    for (int i = 0; i < numSheets; i++)
    {
        listOfSheets.Add(Sheet);
        listOfSheets[i].Name = MockSheetName + (i + 1);
        `mockSheets[i + 1].Returns(listOfSheets[i]);`
    }
    
    0 讨论(0)
  • 2021-01-16 03:46

    This is a reminder to myself everytime I write Nsubstitute Excel Unit Tests. I have battled with this error too many times.

    You will get the error: Cannot perform runtime binding on a null reference

    When you have referened the .Net Excel Object Library, you MUST reference the COM Microsoft Excel 14.0 Object Library. Once the COM interop Excel DLL is referenced, click F4 to see the DLLs Properties, remember to set the COM Interop NOT to Embed Interop Types.

    .Excel Here is a working Project file:

    <ItemGroup>
        <Reference Include="Microsoft.Office.Interop.Excel.Extensions">
          <HintPath>..\..\Refs\Microsoft.Office.Interop.Excel.Extensions.dll</HintPath>
        </Reference>
        <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
        <Reference Include="NSubstitute">
          <HintPath>..\..\Refs\NSubstitute.dll</HintPath>
        </Reference>
        <Reference Include="System" />
        <Reference Include="System.Core">
          <RequiredTargetFramework>3.5</RequiredTargetFramework>
        </Reference>
        <Reference Include="System.Data" />
        <Reference Include="System.Data.DataSetExtensions" />
        <Reference Include="System.Runtime.Serialization" />
        <Reference Include="System.Xml" />
        <Reference Include="System.Xml.Linq" />
        <Reference Include="UIAutomationProvider" />
        <Reference Include="VSTOContrib.Core, Version=0.9.0.52, Culture=neutral, processorArchitecture=MSIL" />
        <Reference Include="WindowsBase" />
        <Reference Include="WindowsFormsIntegration" />
      </ItemGroup>
      <ItemGroup>
        <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
          <Visible>False</Visible>
        </CodeAnalysisDependentAssemblyPaths>
      </ItemGroup>
      <ItemGroup>
        <Compile Include="MockFactory.cs" />
        <Compile Include="Properties\AssemblyInfo.cs" />
        <Compile Include="UnitTests.cs" />
      </ItemGroup>
      <ItemGroup>
          <COMReference Include="Microsoft.Office.Core">
          <Guid>{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}</Guid>
          <VersionMajor>2</VersionMajor>
          <VersionMinor>4</VersionMinor>
          <Lcid>0</Lcid>
          <WrapperTool>primary</WrapperTool>
          <Isolated>False</Isolated>
        </COMReference>
        <COMReference Include="Microsoft.Office.Interop.Excel">
          <Guid>{00020813-0000-0000-C000-000000000046}</Guid>
          <VersionMajor>1</VersionMajor>
          <VersionMinor>6</VersionMinor>
          <Lcid>0</Lcid>
          <WrapperTool>primary</WrapperTool>
          <Isolated>False</Isolated>
        </COMReference>
      </ItemGroup>
    

    The offender is this .Net Interop reference (needs to be the COM reference):

    <Reference Include="Microsoft.Office.Interop.Excel, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL">
      <EmbedInteropTypes>True</EmbedInteropTypes>
    </Reference>
    
    0 讨论(0)
  • 2021-01-16 03:49

    Some history:

    I was getting a compile issue with these errors:

    1.Predefined type 'Microsoft.CSharp.RuntimeBinder.Binder' is not defined or imported
    2.One or more types required to compile a dynamic expression cannot be found. Are you missing references to Microsoft.CSharp.dll and System.Core.dll?

    So I found this article and referenced the Microsoft.CSharp library: C# 4.0 and .Net 3.5

    To the point: The class I've been showing essentially Mocks the Excel Object Model and I copied this class from one project to the other (I cant reference the other project as its actually separate project plus it would have caused circular dependency) I found the Returns extension method was listed in intellisense but I got a "Could not resolve Symbol" when compiling. Even though going to Definition was the same in both classes/projects. To get around this initially I did the commented out lines:

    public static Range Cell
    {
        get
        {
            var mockCell = Substitute.For<Range>();
            mockCell.Address.Returns("$A$1");
            mockCell.Formula = "=1+1";
            mockCell.ToString().Returns(mockCell.Formula.ToString());
            //mockCell.ToString().Returns(info => mockCell.Formula.ToString());
            //SubstituteExtensions.Returns(mockCell.ToString(),  mockCell.Formula.ToString());
            mockCell.Worksheet.Returns(Sheet);
            mockCell.Worksheet.Name.Returns(MockSheetName);
    
            return mockCell;
        }
    }
    

    This point is a bit of a red-herring but removing the Microsoft.CSharp dll actually allowed the Returns extension method to resolve successfully. Then I found removing the Microsoft.CSharp dll resolved my problem, it all just worked, the mockSheet object has all its properties and was able to execute successfully without the "Cannot perform runtime binding on a null reference" error.

    Oh and a tip for anyone Mocking Interop Types, be extra careful to set this:

    enter image description here

    0 讨论(0)
提交回复
热议问题