需要模拟自定义类以进行单元测试
这个问题与我发布的上一个问题相关。
如前所述,我能够将原始代码重构为两个单独的类;我现在尝试通过模拟不依赖于 Office.Interop 对象的部分 (ExcelManager) 来测试不依赖于 Office.Interop 对象的部分 (ParseDataTable)。
当我运行测试时,我的模拟对象仅部分工作,GetColumnCount 方法被正确模拟并返回 ParseDataTable 对象中的局部变量。
但是,并未调用 GetData 模拟方法,而是将代码转入 ExcelManager 类上的 GetData 方法
用于创建模拟的代码:
MockExcel = new Mock<ExcelManager>("testfile.xls",0);
MockExcel.Setup(x => x.GetColumnCount()).Returns(columnCount);
MockExcel.Setup(x => x.GetData()).Returns(mockData);
MockExcel.Setup(x => x.Initialize());
columnCount 和 mockData 都是测试的局部变量,其中包含我的测试所基于的数据。
我正在测试的类:
public class ParseDataTable
{
private const string TableSortOrder = "1 asc, 4 asc, 6 asc";
public DataTable GetRangeValue(ExcelManager excelManager)
{
var columnCount = excelManager.GetColumnCount();
var sheetData = excelManager.GetData();
var value = new DataTable();
for (var j = 1; j <= columnCount; j++)
{
value.Columns.Add(j.ToString());
}
for (var i = 1; i <= sheetData.GetLength(0); i++)
{
var row = value.NewRow();
var emptyCount = 0;
for (var j = 1; j <= columnCount; j++)
{
row[j - 1] = sheetData[i, j] ?? "";
if ((string)row[j-1] == "")
{
emptyCount++;
}
}
//if row is empty then no more data is expected
if (emptyCount == value.Columns.Count) break;
value.Rows.Add(row);
}
excelManager.Dispose();
return sortDataTable(value);
}
private DataTable sortDataTable(DataTable table)
{
table.DefaultView.Sort = TableSortOrder;
table = table.DefaultView.ToTable();
return table;
}
}
ExcelManager 类中需要模拟的方法:
public virtual int GetColumnCount()
{
var headerRng = _worksheet.get_Range(HeaderFirstCell, _miss);
headerRng = headerRng.get_End(XlDirection.xlToRight);
headerRng = _worksheet.get_Range(HeaderFirstCell, headerRng);
var headerData = (object[,])headerRng.Value2;
return headerData.GetLength(1);
}
public virtual object[,] GetData()
{
var last = _worksheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing);
var dataRng = _worksheet.get_Range(DataFirstCell, last);
return (object[,])dataRng.Value2;
}
This question is in relation to a Previous question I posted.
As mentioned i was able to refactor the original code into two separate classes; I am now trying to test the portion (ParseDataTable) that is not reliant upon Office.Interop objects by mocking the portion (ExcelManager) that is.
When I run the tests my mocked object is only partially working, The GetColumnCount method is being properly mocked and returning my local variable within the ParseDataTable object.
However the GetData mocked method is not being called, the code instead goes into the GetData method on the ExcelManager class
The code used to create the mock:
MockExcel = new Mock<ExcelManager>("testfile.xls",0);
MockExcel.Setup(x => x.GetColumnCount()).Returns(columnCount);
MockExcel.Setup(x => x.GetData()).Returns(mockData);
MockExcel.Setup(x => x.Initialize());
columnCount and mockData are both local variables to the test with data that I am basing my tests on.
The class I am testing:
public class ParseDataTable
{
private const string TableSortOrder = "1 asc, 4 asc, 6 asc";
public DataTable GetRangeValue(ExcelManager excelManager)
{
var columnCount = excelManager.GetColumnCount();
var sheetData = excelManager.GetData();
var value = new DataTable();
for (var j = 1; j <= columnCount; j++)
{
value.Columns.Add(j.ToString());
}
for (var i = 1; i <= sheetData.GetLength(0); i++)
{
var row = value.NewRow();
var emptyCount = 0;
for (var j = 1; j <= columnCount; j++)
{
row[j - 1] = sheetData[i, j] ?? "";
if ((string)row[j-1] == "")
{
emptyCount++;
}
}
//if row is empty then no more data is expected
if (emptyCount == value.Columns.Count) break;
value.Rows.Add(row);
}
excelManager.Dispose();
return sortDataTable(value);
}
private DataTable sortDataTable(DataTable table)
{
table.DefaultView.Sort = TableSortOrder;
table = table.DefaultView.ToTable();
return table;
}
}
Methods within the ExcelManager class that need to be mocked:
public virtual int GetColumnCount()
{
var headerRng = _worksheet.get_Range(HeaderFirstCell, _miss);
headerRng = headerRng.get_End(XlDirection.xlToRight);
headerRng = _worksheet.get_Range(HeaderFirstCell, headerRng);
var headerData = (object[,])headerRng.Value2;
return headerData.GetLength(1);
}
public virtual object[,] GetData()
{
var last = _worksheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing);
var dataRng = _worksheet.get_Range(DataFirstCell, last);
return (object[,])dataRng.Value2;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您从 ExcelManager 中提取一个接口作为接口(您可以将其称为 IExcelManager,但告诉大家我想出了一个绝妙的名字:-),那不是更容易吗?如果你通过了这一点,你的嘲笑困难应该不那么痛苦。
Wouldn't it be much easier if you extracted an interface from ExcelManager as an interface (you can call it IExcelManager, but tell everybody that i came up with the brilliant name :-) ? If you passed that instead your mocking difficulties should be less of a pain.