Recientemente, pregunté (y respondí) una pregunta sobre StackOverflow sobre por qué funcionaría una prueba unitaria cuando se ejecuta sola y luego falla esporádicamente cuando se ejecuta con todo el lote de pruebas unitarias. Vea aquí: SQL Server and TransactionScope (with MSDTC): Sporadically can't get connection¿Cómo funciona el recolector de basura con las pruebas unitarias?
Las pruebas unitarias que pasan al ejecutarse de a una por vez y luego fallan cuando se ejecutan juntas es un signo clásico de que algo está muy mal con el código.
Descubrí que hay un poco de fuga de recursos. Debido a un error sutil que causaba que las conexiones con un servidor SQL no se publicaran, me estaba quedando sin conexiones y las pruebas estaban fallando. AFAIK, esto funciona casi exactamente como una pérdida de memoria; las conexiones se asignan desde un grupo de conexiones y nunca se liberan del mismo modo que se puede asignar la memoria y luego no se libera.
Sin embargo, esto me deja con una pregunta desconcertante? ¿Cuál es la diferencia entre ejecutar mis pruebas de una en una y ejecutarlas como una suite? Si las pruebas pasan cuando se ejecutan de una en una y luego fallan cuando se ejecutan juntas, entonces debe haber algún tipo de limpieza entre las ejecuciones de prueba que ocurre solo cuando las pruebas se ejecutan de a una por vez.
Supongo que esto podría tener algo que ver con lo que el recolector de basura .net hace o no entre las pruebas. En un caso, las conexiones se liberan entre pruebas; en otro caso, no lo son.
¿Cómo puedo explicar esto?
Actualización: Para aquellos de ustedes que preguntan sobre los detalles del código, es bastante simple. Declaro un nuevo objeto TransactionScope
en mi método de configuración y lo elimino en mi método Teardown
. Sin embargo, la prueba del problema fue una prueba basada en datos con 100 casos de prueba; el código bajo prueba llenó un objeto SqlDataReader
de una declaración de selección usando la clase SqlHelper y luego no llamó al método de cierre en el SqlDataReader
. Como utilicé la clase SqlHelper para obtener el SqlDataReader, esperaba que las conexiones se manejaran por mí. ¡No tan!
Pero para aclarar, no estoy preguntando sobre mi situación específica. Lo que quiero saber es: en general, ¿cómo se liberan los recursos entre las pruebas? Me imagino que esto sería una aplicación del recolector de basura. Me pregunto si el recolector de basura todavía podría estar limpiando una prueba anterior mientras se ejecuta la siguiente prueba (¿condición de carrera?)
Actualización: Lo que sé sobre la recolección de basura con pruebas unitarias. Siguiendo mi propia curiosidad, saqué las pruebas unitarias que estaban fallando porque el objeto SqlDataReader
dejó abierta una conexión. Traté de agregar System.GC.Collect()
al final de cada prueba. Esto liberó con éxito las conexiones, pero impone una penalización de rendimiento del ~ 50%.
Si se está quedando sin conexiones porque no las libera lo suficiente entre pruebas, sospecho que hay un problema con sus métodos de extracción. Al ejecutarlos de a uno por vez, el sistema operativo se encarga de reducir un poco, pero se ejecuta como un conjunto de aplicaciones que su uso de recursos persiste por más tiempo. – MikeD
Tal vez solo necesite algunas llamadas 'Dispose' o' Close' en alguna parte. – Gabe