在模拟Workbook-> Worksheets时:从范围”引用的类型为'Microsoft.Office.Interop.Excel.Workbook'的变量'p',但未定义

时间:2019-02-15 11:13:47

标签: c# linq unit-testing mocking excel-interop

我刚刚开始学习如何在NUnit中使用单元测试,以及如何使用模拟来伪造需要测试的对象。

目前,我正在与一个实现VSTO Excel Addin的项目一起工作,并希望开始对该项目使用单元测试。

因此,我有一个函数以工作簿为参数,并返回要处理的相关工作表的列表。 我想测试一下这个功能。我“只是”需要伪造工作表名称,因为该功能只会遍历所有工作表并检查其名称。

通过搜索Internet资源,我试图构建以下解决方案,以假冒带有名称为“ SheetNames”的工作表列表的工作簿,该工作表的类型为List:

        var fakeWorksheetList = new List<Excel.Worksheet>();
        foreach (string sheetName in SheetNames)
        {
            var sheet = Mock.Of<Excel.Worksheet>();
            sheet.Name = sheetName;
            fakeWorksheetList.Add(sheet);
        }

        var fakeWorkbook = new Mock<Excel.Workbook>();
        fakeWorkbook.Setup(p => p.Worksheets.GetEnumerator())
            .Returns(() => fakeWorksheetList.GetEnumerator());

但是运行测试代码时,出现以下错误消息:

variable "p" of type "Microsoft.Office.Interop.Excel.Workbook" referenced from scope "", but it is not defined

我在做什么错。为什么Setup()中的lambda表达式会给我这样的错误消息? 有没有更好的伪造工作表列表的方法?

如果我表现出一些理解上的欠缺,请原谅我,因为我真的只是从嘲笑话题入手。

这是我要测试的功能,我需要在我的外接程序中获取该外接程序必须使用的所有工作表:

    public static Dictionary<int, Excel.Worksheet> GetApplicableYearSheets(Excel.Workbook Workbook, int iCurrentYear = 0)
    {
        if (iCurrentYear <= 0)
            iCurrentYear = DateTime.Now.Year;

        int iFromYear = iCurrentYear - 2;
        Dictionary<int, Excel.Worksheet> YearSheets = new Dictionary<int, Excel.Worksheet>();

        for (int iNr = 1; iNr <= Workbook.Worksheets.Count; iNr++)
        {
            int iYear = 0;
            string sWorksheetName = Workbook.Worksheets[iNr].Name;
            if ((sWorksheetName.Trim().Length == 4) && (int.TryParse(sWorksheetName, out iYear)))
            {
                if ((iYear >= iFromYear) && (iYear <= iCurrentYear))
                    YearSheets.Add(iYear, Workbook.Worksheets[iNr]);
            }
        }

        return YearSheets;
    }

我要用于测试的工作表名称列表例如:

        List<string> SheetNames = new List<string>()
        {
            "2012",
            "2013",
            "2014",
            "2015",
            "2016",
            "2017",
            "2018",
            "2019",
            "Test",
            "Spezialfälle"
        };

我的计划是使用模拟的fakeWorkbook测试调用此函数的方式,例如,如下所示:

Assert.That(InvoicingUtils.GetApplicableYearSheets(FakeWbFullNames, iCurrentYear: 2019), Has.Exactly(3).Items);

以此类推

1 个答案:

答案 0 :(得分:1)

我认为有一种更好,更优雅的方式来编写模拟代码,但这对我有用。
请注意:
 -我将Moq用作模拟框架。我相信你用相同的
 -我只将IDictionary遇到了一些问题,因此将您的方法的返回类型更改为Dictionary

代码:
   -为了初始化测试表,您可以使用循环。我只是简单了一下,只创建了两张纸,没有任何循环。
   -我认为您只需在workbook对象上进行少量设置就可以使它工作,但我喜欢这种方式(只是个人喜好
   -如您所见,整个逻辑在sheets对象上运行。基本上,我从生产代码中获得一个索引,将-1减去即可得到从零开始的索引,将其保存到变量sheetIndex中,然后从worksheets集合中返回一个假表

using System.Collections.Generic;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace ExcelMocking.Tests
{
    [TestClass]
    public class UnitTest1
    {
        private List<Excel.Worksheet> worksheets = new List<Excel.Worksheet>();

        [TestMethod]
        public void TestMethod1()
        {
            var sheet = new Mock<Excel.Worksheet>();
            sheet.SetupGet(w => w.Name).Returns("2012");
            worksheets.Add(sheet.Object);

            sheet = new Mock<Excel.Worksheet>();
            sheet.SetupGet(w => w.Name).Returns("2013");
            worksheets.Add(sheet.Object);

            var sheetIndex = 0;
            var sheets = new Mock<Excel.Sheets>();
            sheets.Setup(s => s.Count).Returns(() => worksheets.Count);
            sheets.Setup(s => s[It.IsAny<object>()]).Callback<object>((theSheetIndex) =>
            {
                // getting the real sheet index from the production code that starts from 1
                // and simple subtracting -1 to get zero based index
                sheetIndex = (int)theSheetIndex;
                sheetIndex--;
            }).Returns(() => worksheets[sheetIndex]);

            sheets.Setup(s => s.GetEnumerator()).Returns(() => worksheets.GetEnumerator());
            sheets.As<Excel.Sheets>().Setup(s => s.GetEnumerator()).Returns(() => worksheets.GetEnumerator());

            var workbook = new Mock<Excel.Workbook>();
            workbook.Setup(w => w.Worksheets).Returns(sheets.Object);            

            IDictionary<int, Excel.Worksheet> result = ExcelMocking.Class1.GetApplicableYearSheets(workbook.Object);
        }
    }
}