c# - 如何测试在被测类中调用的方法?

标签 c# unit-testing refactoring nunit rhino-mocks

首先我会说我是单元测试的新手,我想开始使用 TDD 方法,但现在我正在为一些现有类编写单元测试以验证它们在所有情况下的功能。

我已经能够毫不费力地使用 NUnit 和 Rhino 模拟测试我的大部分代码。但是,我一直想知道单元测试函数最终会调用同一类中的许多其他方法。我不能做类似的事情

classUnderTest.AssertWasCalled(cut => cut.SomeMethod(someArgs))

因为被测类不是假的。此外,如果我正在测试的方法调用被测类中的其他方法,而这些方法又调用同一类中的方法,那么我将需要伪造大量值来测试“顶级”方法。因为我也在对所有这些“子方法”进行单元测试,所以我应该能够假设“SomeMethod”在通过单元测试时按预期工作,而不需要担心那些低级方法的细节。

这是我一直在使用的一些示例代码,以帮助说明我的观点(我编写了一个类来使用 NPOI 管理 Excel 文件的导入/导出):

    public DataSet ExportExcelDocToDataSet(bool headerRowProvided)
    {
        DataSet ds = new DataSet();

        for (int i = 0; i < currentWorkbook.NumberOfSheets; i++)
        {               
            ISheet tmpSheet = currentWorkbook.GetSheetAt(i);

            if (tmpSheet.PhysicalNumberOfRows == 0) { continue; }
            DataTable dt = GetDataTableFromExcelSheet(headerRowProvided, ds, tmpSheet);

            if (dt.Rows.Count > 0)
            {
                AddNonEmptyTableToDataSet(ds, dt);
            }
        }

        return ds;
    }

    public DataTable GetDataTableFromExcelSheet(bool headerRowProvided, DataSet ds, ISheet tmpSheet)
    {
        DataTable dt = new DataTable();
        for (int sheetRowIndex = 0; sheetRowIndex <= tmpSheet.LastRowNum; sheetRowIndex++)
        {
            DataRow dataRow = GetDataRowFromExcelRow(dt, tmpSheet, headerRowProvided, sheetRowIndex);
            if (dataRow != null && dataRow.ItemArray.Count<object>(obj => obj != DBNull.Value) > 0)
            {
                dt.Rows.Add(dataRow);
            }
        }

        return dt;
    }

...

您可以看到 ExportExcelDocToDataSet(在本例中是我的“顶级”方法)调用了 GetDataTableFromExcelSheet,后者调用了 GetDataRowFromExcelRow,后者调用了在同一个类中定义的几个其他方法。

那么重构此代码以使其更易于单元测试而不必 stub 子方法调用的值的推荐策略是什么?有没有办法在被测类中伪造方法调用?

在此先感谢您的帮助或建议!

最佳答案

修改主题under test (SUT) .如果某些东西难以进行单元测试,那么设计可能会很尴尬。

在被测类中伪造方法调用会导致过度指定的测试。结果是非常脆弱的测试:一旦你修改或重构类,那么很可能你还需要修改单元测试。这导致单元测试的维护成本过高。

为避免过度指定的测试,请专注于公共(public)方法。如果此方法调用类中的其他方法,请不要测试这些调用。另一方面:方法调用其他 dependend on component (DOCs)应该进行测试。

如果您坚持这样做并感觉您在测试中错过了一些重要的事情,那么这可能是一个类或方法做得太多的标志。如果是类:寻找违反 Single Responsibility Principle (SRP) 的行为.从中提取类并单独测试它们。如果是方法:将方法拆分为多个公共(public)方法并分别测试每个方法。如果这仍然太尴尬,您肯定有一个类违反了 SRP。

在您的特定情况下,您可以执行以下操作:将方法 ExportExcelDocToDataSetGetDataTableFromExcelSheet 提取到两个不同的类中(可以将它们称为 ExcelToDataSetExporterExcelSheetToDataTableExporter)。包含这两个方法的原始类应该引用这两个类并调用您之前提取的那些方法。现在您可以单独测试所有三个类。申请 Extract Class refactoring ( book ) 来实现对原始类的修改。

另请注意, retrofit 测试的编写和维护总是有点麻烦。原因是在没有单元测试的情况下编写的 SUT 往往设计笨拙,因此更难测试。这意味着单元测试的问题必须通过修改 SUT 来解决,而不是通过拉动单元测试来解决。

关于c# - 如何测试在被测类中调用的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9657849/

相关文章:

unit-testing - 测试自耕农的 composeWith

ruby-on-rails - 什么是等效于惰性求值范围的 Rails ActiveRecord find(x) 方法?如何重构 ActiveRecord 查找器?

c++ - 运行现有应用程序以更改数据库,好主意吗?

c# - c#中方法隐藏的优点和缺点?

c# - 没有弹出窗口,错误源是rdr = cmd.executereader();

c# - 如何更新 ModelStateDictionary 中的错误值?

javascript - 为了进行单元测试,可以在 JavaScript 中创建大量类吗?

unit-testing - 找不到符号导入 dagger.hilt.android.internal.Contexts

python - 如何改进代码,减少代码量?

C# NotFiniteNumberException 不起作用