expected c# exception-handling assert

c# - expected - Debug.Assert frente a excepciones específicas arrojadas



mstest assert exception (8)

Acabo de comenzar a robar ''Debugging MS .Net 2.0 Applications'' de John Robbins, y me he confundido por su evangelismo para Debug.Assert (...).

Señala que Asserts bien implementado almacena el estado, algo así como una condición de error, por ejemplo:

Debug.Assert(i > 3, "i > 3", "This means I got a bad parameter");

Ahora, personalmente, me parece una locura que a él le encanta reafirmar su examen sin un comentario sensato de ''lógica de negocios'', tal vez "nunca debería suceder i <= 3 debido al proceso de ambigüedad de flobittyjam".

Por lo tanto, creo que aparece Asserts como una clase de bajo nivel "Protejamos mis suposiciones" ... suponiendo que uno siente que esta es una prueba que solo se necesita para depurar, es decir, que se está protegiendo contra un colega y futuros programadores, y con la esperanza de que realmente prueben cosas.

Pero lo que no entiendo es que luego agrega que debe usar aserciones además del manejo normal de errores; ahora lo que pretendo es algo como esto:

Debug.Assert(i > 3, "i must be greater than 3 because of the flibbity widgit status"); if (i <= 3) { throw new ArgumentOutOfRangeException("i", "i must be > 3 because... i=" + i.ToString()); }

¿Qué obtuve con la depuración? ¿Repito la repetición de la prueba de condición de error? Creo que lo conseguiría si estuviéramos hablando de una doble verificación de un cálculo muy importante ...

double interestAmount = loan.GetInterest(); Debug.Assert(debugInterestDoubleCheck(loan) == interestAmount, "Mismatch on interest calc");

... pero no lo obtengo para las pruebas de parámetros que seguramente vale la pena verificar (tanto en versiones DEBUG como en versiones de Release) ... o no. ¿Qué me estoy perdiendo?


Hay un aspecto de comunicación para afirmar frente a lanzamiento de excepción.

Digamos que tenemos una clase de usuario con una propiedad Name y un método ToString.

Si ToString se implementa de esta manera:

public string ToString() { Debug.Assert(Name != null); return Name; }

Dice que Name nunca debe anularse y que hay un error en la clase User si lo es.

Si ToString se implementa así:

public string ToString() { if ( Name == null ) { throw new InvalidOperationException("Name is null"); } return Name; }

Dice que la persona que llama está usando ToString incorrectamente si Name es nulo y debería verificarlo antes de llamar.

La implementación con ambos

public string ToString() { Debug.Assert(Name != null); if ( Name == null ) { throw new InvalidOperationException("Name is null"); } return Name; }

dice que si Name es nulo, hay un error en la clase User, pero queremos manejarlo de todos modos. (El usuario no necesita verificar el nombre antes de llamar). Creo que este es el tipo de seguridad que Robbins recomendaba.


IMO es solo una pérdida de tiempo de desarrollo. La excepción implementada correctamente le da una idea clara de lo que sucedió. Vi demasiadas aplicaciones que mostraban oscuros errores de "Error de aserción: i <10". Veo la afirmación como una solución temporal. En mi opinión, ninguna afirmación debe estar en una versión final de un programa. En mi práctica usé aserciones para verificaciones rápidas y sucias. La versión final del código debe tener en cuenta la situación errónea y comportarse en consecuencia. Si sucede algo malo, tienes 2 opciones: manejarlo o dejarlo. La función debe arrojar una excepción con una descripción significativa si se pasan los parámetros incorrectos. No veo puntos en duplicación de la lógica de validación.


Las afirmaciones no son para la verificación de parámetros. La verificación de parámetros siempre debe hacerse (y de acuerdo con las condiciones previas especificadas en su documentación y / o especificación), y la ArgumentOutOfRangeException arrojada según sea necesario.

Las afirmaciones son para probar situaciones "imposibles", es decir, cosas que usted (en su lógica de programa) asume que son verdaderas. Las afirmaciones están ahí para decirle si estas suposiciones se rompen por algún motivo.

¡Espero que esto ayude!


Se puede capturar y eliminar una excepción, haciendo que el error sea invisible para la prueba. Eso no puede suceder con Debug.Assert.

Nadie debería tener un controlador de capturas que capte todas las excepciones, pero la gente lo hace de todos modos, y algunas veces es inevitable. Si se invoca su código desde COM, la capa de interoperabilidad captura todas las excepciones y las convierte en códigos de error COM, lo que significa que no verá las excepciones no controladas. Las afirmaciones no sufren de esto.

Además, cuando la excepción no se maneja, una práctica aún mejor es tomar un mini-volcado. Un área donde VB es más poderosa que C # es que puede usar un filtro de excepción para hacer un mini-volcado cuando la excepción está en vuelo, y dejar sin cambios el resto del manejo de excepciones. La publicación del blog de Gregg Miskelly sobre inyección de filtros de excepción proporciona una forma útil de hacerlo desde c #.

Otra nota sobre los activos ... no interactúan mal con la Unidad que prueba las condiciones de error en su código. Vale la pena tener un contenedor para desactivar la afirmación de las pruebas unitarias.


Utilizo comprobaciones explícitas que arrojan excepciones sobre métodos y afirmaciones públicos y protegidos en métodos privados.

Normalmente, las comprobaciones explícitas evitan que los métodos privados vean valores incorrectos de todos modos. Entonces, realmente, el afirmado está buscando una condición que debería ser imposible. Si una afirmación dispara, me dice que hay un defecto en la lógica de validación contenida dentro de una de las rutinas públicas en la clase.


Aquí está por 2 centavos.

Creo que la mejor manera es usar ambas aserciones y excepciones. Las principales diferencias entre los dos métodos, si las declaraciones de Assert se pueden eliminar fácilmente del texto de la aplicación (define, atributos condicionales ...), mientras que la excepción lanzada depende (típicamente) de un código condicional que es más difícil de eliminar ( sección múltiple con condicionales de preprocesador).

Cada excepción de aplicación se manejará correctamente, mientras que las afirmaciones se satisfarán solo durante el desarrollo y la prueba del algoritmo.

Si pasa una referencia de objeto nulo como parámetro de rutina y usa este valor, obtiene una excepción de puntero nulo. De hecho: ¿por qué deberías escribir una afirmación? Es una pérdida de tiempo en este caso. Pero, ¿qué pasa con los miembros privados de la clase que se usan en las rutinas de la clase? Cuando estos valores se establecen en algún lugar, es mejor verificar con una aserción si se establece un valor nulo. Eso es solo porque cuando usa el miembro, obtiene una excepción de puntero nulo pero no sabe cómo se estableció el valor. Esto causa un reinicio del programa rompiendo todo el uso del punto de entrada para establecer el miembro privado.

Las excepciones son más útiles, pero pueden ser (muy) muy difíciles de gestionar y existe la posibilidad de utilizar demasiadas excepciones. Y requieren una verificación adicional, tal vez no deseada para optimizar el código. Personalmente uso excepciones solo cuando el código requiere un control de captura profundo (las declaraciones de captura son muy bajas en la pila de llamadas) o cuando los parámetros de la función no están codificados en el código.


He pensado mucho sobre esto cuando se trata de proporcionar una guía sobre la depuración frente a la afirmación con respecto a las preocupaciones de las pruebas.

Debería poder probar su clase con entradas erróneas, mal estado, orden de operaciones inválido y cualquier otra condición de error concebible y una afirmación nunca debería dispararse. Cada afirmación está comprobando que algo siempre debe ser cierto independientemente de las entradas o cálculos realizados.

Buenas reglas prácticas a las que he llegado:

  1. Las afirmaciones no son un reemplazo del código robusto que funciona correctamente independientemente de la configuración. Ellos son complementarios.

  2. Las afirmaciones nunca se deben disparar durante una ejecución de prueba de unidad, incluso cuando se introducen valores no válidos o pruebas de condiciones de error. El código debe manejar estas condiciones sin que ocurra una afirmación.

  3. Si un afirmativo se dispara (ya sea en una prueba unitaria o durante la prueba), la clase tiene errores.

Para todos los demás errores, normalmente hasta el entorno (pérdida de conexión de red) o uso indebido (la persona que llama pasó un valor nulo), es mucho más agradable y más comprensible usar controles y excepciones. Si ocurre una excepción, la persona que llama sabe que es probable que sea su culpa. Si se produce una afirmación, la persona que llama sabe que es probable que haya un error en el código donde se encuentra la declaración.

En cuanto a la duplicación: estoy de acuerdo. No veo por qué debería replicar la validación con un Debug.Assert Y una verificación de excepción. No solo agrega algo de ruido al código y enturbia las aguas con respecto a quién tiene la culpa, sino que es una forma de repetición.


Ejemplo de un buen uso de Assert:

Debug.Assert(flibbles.count() < 1000000, "too many flibbles"); // indicate something is awry log.warning("flibble count reached " + flibbles.count()); // log in production as early warning

Personalmente, creo que Assert solo debe usarse cuando sabes que algo está fuera de los límites deseables , pero puedes estar seguro de que es razonablemente seguro continuar. En todas las demás circunstancias (no dude en señalar las circunstancias en las que no he pensado) use excepciones para fallar de manera rápida y difícil.

La clave para mí es si quieres derribar un sistema en vivo / producción con una excepción para evitar corrupción y facilitar la resolución de problemas, o si has encontrado una situación que nunca debería permitirse que continúe desapercibida en las versiones de prueba / depuración, pero podría se le permitirá continuar en producción (registrando una advertencia por supuesto).

cf. http://c2.com/cgi/wiki?FailFast copiado y modificado de la pregunta de Java: Excepción Vs Afirmación