Comenzaré diciendo que soy bastante nuevo en pruebas unitarias y me gustaría comenzar a usar un enfoque TDD, pero por el momento estoy escribiendo pruebas unitarias para algunas clases existentes para verificar su funcionalidad en todos los casos.¿Cómo se prueba que se llamó un método dentro de una clase bajo prueba?
He podido probar la mayoría de mi código usando NUnit y Rhino se burla sin muchos problemas. Sin embargo, me he estado preguntando acerca de las funciones de pruebas unitarias que terminan llamando a muchos otros métodos dentro de la misma clase. No puedo hacer algo como
classUnderTest.AssertWasCalled(cut => cut.SomeMethod(someArgs))
porque la clase bajo prueba no es falsa. Además, si un método que estoy probando llama a otros métodos en la clase bajo prueba que a su vez también llaman a métodos en la misma clase, voy a necesitar falsificar una tonelada de valores solo para probar el método de "nivel superior". Dado que también estoy probando de forma unitaria todos estos "submétodos", debería poder asumir que "SomeMethod" funciona como se espera si pasa la prueba de la unidad y no necesita preocuparse por los detalles de esos métodos de nivel inferior.
Aquí es un código de ejemplo que he estado trabajando con para ayudar a ilustrar mi punto (He escrito una clase para manejar la importación/exportación de archivos Excel utilizando 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;
}
...
Se puede ver que ExportExcelDocToDataSet (mi método de "alto nivel" en este caso) llama GetDataTableFromExcelSheet que exige GetDataRowFromExcelRow, que llama a un par de otros métodos que se definen dentro de esta misma clase.
Entonces, ¿cuál es la estrategia recomendada para refaccionar este código para que sea más comprobable por unidad sin tener que insertar valores llamados por submétodos? ¿Hay alguna manera de falsificar llamadas a métodos dentro de la clase bajo prueba?
Gracias de antemano por cualquier ayuda o consejo!
Pensé en extraer los métodos que mencionaste en clases separadas para poder probarlos en una unidad usando la extensión AssertWasCalled, pero no estaba seguro de si esta era una gran idea porque podía ver eso dando lugar a un montón de clases muy superficiales con uno o dos métodos en ellos como máximo. Definitivamente revisaré el libro que recomendó y también más sobre el SRP. Lo mejor de todo esto es que soy la única persona en el proyecto y todo el código ha sido escrito por mí, por lo que puedo hacer lo que sea necesario para que funcione. –
@Gage Trader: no mida una clase en términos de números de métodos. Por ejemplo, el patrón de comando expone solo un método y todavía es una técnica utilizada ampliamente. Antes de aplicar pruebas unitarias y buenos principios de diseño OO, no me sentía cómodo con la mayor cantidad de clases. Me tomó un tiempo darme cuenta de que un mayor número de clases no significa más trabajo. Sí, es cierto que necesita más tiempo para el diseño y las pruebas, pero la mayor calidad y el menor número de errores lo compensa con creces. –