Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need to mock a custom class for unit testing purposes

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;
    }
like image 311
Justin Avatar asked Nov 15 '22 00:11

Justin


1 Answers

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.

like image 154
Morten Avatar answered Dec 07 '22 23:12

Morten