Начну с того, что я довольно новичок в модульном тестировании, и я бы хотел начать использовать TDD-подход, но сейчас я пишу модульные тесты для некоторых существующих классов, чтобы проверить их функциональность во всех случаях.Как проверить метод, вызванный внутри тестируемого класса?
Я смог протестировать большую часть своего кода, используя NUnit и Rhino, без особых проблем. Тем не менее, мне было интересно узнать о функциях модульного тестирования, которые в конечном итоге вызывают множество других методов в одном классе. Я не могу сделать что-то вроде
classUnderTest.AssertWasCalled(cut => cut.SomeMethod(someArgs))
потому что испытанный класс не является подделкой. Кроме того, если метод, который я тестирую, вызывает другие методы в тестируемом классе, который, в свою очередь, также вызывает методы в одном классе, мне нужно будет подделать тонну значений, чтобы проверить метод «верхнего уровня». Поскольку я также тестирую все эти «вспомогательные методы», я должен уметь предположить, что «SomeMethod» работает так, как ожидалось, если он проходит модульный тест и не нуждается в подробностях о тех методах нижнего уровня.
Вот несколько примеров кода я работаю с, чтобы проиллюстрировать мою точку зрения (я написал класс для управления импорта/экспорта файлов Excel с использованием NPOI):
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, который вызывает несколько других методов, которые определены в этом же классе.
Итак, какова рекомендуемая стратегия для рефакторинга этого кода, чтобы сделать его более универсальным, без необходимости заглушать значения, называемые субметодами? Есть ли способ подделывать вызовы методов внутри тестируемого класса?
Заранее благодарим за любую помощь или совет!
Я подумал об извлечении методов, которые вы упомянули, в отдельные классы, чтобы я мог тестировать их с помощью расширения AssertWasCalled, но я не был уверен, что это отличная идея, потому что я мог видеть, что это приводит к тонне очень мелких классов с один или два метода в них не более. Я обязательно просмотрю рекомендованную вами книгу, а также больше о SRP. Самое лучшее во всем этом - я единственный человек в проекте, и весь код написан мной, поэтому я могу делать все, что мне нужно, чтобы он работал. –
@Gage Trader: не измеряйте класс по количеству методов. Например, Command Pattern предоставляет только один метод и по-прежнему является используемым методом. Прежде чем я применил модульное тестирование и хорошие принципы проектирования OO, мне не нравилось большее количество классов. Я взял время, чтобы понять, что большее число классов не означает больше работы. Да, это правда, что вам нужно больше времени для разработки и тестирования, но более высокое качество и более низкий показатель ошибок компенсируют это на сегодняшний день. –