需要模拟自定义类以进行单元测试

发布于 2024-10-31 00:18:07 字数 2647 浏览 0 评论 0原文

这个问题与我发布的上一个问题相关。

如前所述,我能够将原始代码重构为两个单独的类;我现在尝试通过模拟不依赖于 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

金兰素衣 2024-11-07 00:18:07

如果您从 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文