我刚刚开始学习如何在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);
以此类推
答案 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);
}
}
}