throwsexception expected example c# exception assertions

c# - expected - assert.throwsexception example



Debug.Assert vs Exception Throwing (7)

Aunque estoy de acuerdo en que su razonamiento es plausible , es decir, si una afirmación es violada de manera inesperada, tiene sentido detener la ejecución arrojándola, yo personalmente no usaría excepciones en el lugar de las afirmaciones. Este es el por qué:

Como han dicho otros, las afirmaciones deben documentar situaciones que son imposibles , de tal manera que si la situación supuestamente imposible llega a pasar, se informa al desarrollador. Las excepciones, por el contrario, proporcionan un mecanismo de flujo de control para situaciones excepcionales, improbables o erróneas, pero no situaciones imposibles. Para mí, la diferencia clave es esta:

  • SIEMPRE debería ser posible producir un caso de prueba que ejerza una declaración de lanzamiento determinada. Si no es posible producir un caso de prueba, entonces tiene una ruta de código en su programa que nunca se ejecuta, y debe eliminarse como código muerto.

  • NUNCA debería ser posible producir un caso de prueba que provoque que se active una afirmación. Si se activa una afirmación, o el código es incorrecto o la afirmación es incorrecta; De cualquier manera, algo necesita cambiar en el código.

Es por eso que no reemplazaría una afirmación con una excepción. Si la afirmación no puede realmente activarse, reemplazarla con una excepción significa que tiene una ruta de código no comprobable en su programa . No me gustan las rutas de códigos no comprobables.

He leído muchos articles (y un par de preguntas similares publicadas en StackOverflow) sobre cómo y cuándo usar las afirmaciones, y las entendí bien. Pero aún así, no entiendo qué tipo de motivación debería llevarme a utilizar Debug.Assert lugar de arrojar una simple excepción. Lo que quiero decir es que, en .NET, la respuesta predeterminada a una afirmación fallida es "detener el mundo" y mostrar un cuadro de mensaje al usuario. Aunque este tipo de comportamiento podría modificarse, me resulta muy molesto y redundante hacer eso, mientras que podría, en su lugar, lanzar una excepción adecuada. De esta forma, podría escribir fácilmente el error en el registro de la aplicación justo antes de arrojar la excepción, y además, mi aplicación no necesariamente se congela.

Entonces, ¿por qué debería, si es que lo hago, usar Debug.Assert lugar de una simple excepción? Poner una afirmación donde no debería ser podría causar todo tipo de "comportamientos no deseados", así que desde mi punto de vista, realmente no gano nada al usar una afirmación en lugar de lanzar una excepción. ¿Estás de acuerdo conmigo o me estoy perdiendo algo aquí?

Nota: Entiendo completamente cuál es la diferencia "en teoría" (depuración frente a versión, patrones de uso, etc.), pero a mi modo de ver, sería mejor que lanzara una excepción en lugar de realizar una afirmación. Dado que si se descubre un error en una versión de producción, aún me gustaría que falle la "afirmación" (después de todo, la "sobrecarga" es ridículamente pequeña), así que será mejor que haga una excepción.

Editar: La forma en que lo veo, si una afirmación falla, eso significa que la aplicación entró en algún tipo de estado corrupto e inesperado. Entonces, ¿por qué querría continuar la ejecución? No importa si la aplicación se ejecuta en una versión de depuración o versión. Lo mismo aplica para ambos


Creo que un ejemplo práctico (artificial) puede ayudar a iluminar la diferencia:

(adaptado de la extensión por lotes de MoreLinq )

// ''public facing'' method public int DoSomething(List<string> stuff, object doohickey, int limit) { // validate user input and report problems externally with exceptions if(stuff == null) throw new ArgumentNullException("stuff"); if(doohickey == null) throw new ArgumentNullException("doohickey"); if(limit <= 0) throw new ArgumentOutOfRangeException("limit", limit, "Should be > 0"); return DoSomethingImpl(stuff, doohickey, limit); } // ''developer only'' method private static int DoSomethingImpl(List<string> stuff, object doohickey, int limit) { // validate input that should only come from other programming methods // which we have control over (e.g. we already validated user input in // the calling method above), so anything using this method shouldn''t // need to report problems externally, and compilation mode can remove // this "unnecessary" check from production Debug.Assert(stuff != null); Debug.Assert(doohickey != null); Debug.Assert(limit > 0); /* now do the actual work... */ }

Así como Eric Lippert y otros han dicho, solo afirmas cosas que esperas que sean correctas, solo en caso de que (el desarrollador) las haya usado incorrectamente en otro lugar, para que puedas corregir tu código. Básicamente, se lanzan excepciones cuando no se tiene control o no se puede anticipar lo que entra, por ejemplo , por la entrada del usuario , para que cualquier cosa que haya dado datos erróneos pueda responder adecuadamente (por ejemplo, el usuario).


Debug.Assert de forma predeterminada solo funcionará en compilaciones de depuración, por lo que si desea detectar cualquier tipo de comportamiento incorrecto inesperado en las compilaciones de lanzamiento, deberá usar excepciones o activar la constante de depuración en las propiedades de su proyecto (que se considera en general no es una buena idea).


Las afirmaciones se utilizan para verificar la comprensión del mundo por parte del programador. Una afirmación debería fallar solo si el programador ha hecho algo mal. Por ejemplo, nunca use una aserción para verificar la entrada del usuario.

Afirma la prueba de condiciones que "no pueden suceder". Las excepciones son para condiciones que "no deberían suceder sino hacer".

Las afirmaciones son útiles porque en tiempo de compilación (o incluso tiempo de ejecución) puede cambiar su comportamiento. Por ejemplo, a menudo en compilaciones de lanzamiento, las afirmaciones ni siquiera están marcadas, porque introducen gastos indirectos innecesarios. Esto también es algo de lo que hay que desconfiar: es posible que sus pruebas ni siquiera se ejecuten.

Si usa excepciones en lugar de aseveraciones, pierde algún valor:

  1. El código es más detallado, ya que probar y lanzar una excepción es de al menos dos líneas, mientras que una afirmación es solo una.

  2. Su código de prueba y tiro siempre se ejecutará, mientras que las afirmaciones pueden compilarse.

  3. Pierdes algo de comunicación con otros desarrolladores, porque las afirmaciones tienen un significado diferente al código de producto que verifica y arroja. Si realmente está probando una aserción de programación, use una afirmación.

Más aquí: http://nedbatchelder.com/text/assert.html


Otra pepita de Code Complete :

"Una aserción es una función o macro que se queja en voz alta si una suposición no es verdadera. Use las aserciones para documentar las suposiciones hechas en el código y para eliminar las condiciones inesperadas ...

"Durante el desarrollo, las aserciones eliminan suposiciones contradictorias, condiciones inesperadas, malos valores pasados ​​a las rutinas, etc."

Continúa agregando algunas pautas sobre lo que se debe y no se debe afirmar.

Por otro lado, excepciones:

"Utilice el manejo de excepciones para llamar la atención sobre casos inesperados. Los casos excepcionales deben manejarse de una manera que los haga obvios durante el desarrollo y recuperables cuando se esté ejecutando el código de producción".

Si no tiene este libro, debe comprarlo.


Use afirmaciones para cosas que SON posibles pero que no deberían suceder (si fuera imposible, ¿por qué pondría una afirmación?).

¿No suena como un caso para usar una Exception ? ¿Por qué usarías una afirmación en lugar de una Exception ?

Porque debería haber un código que se llame antes de su aserción que detendría el parámetro de la aserción siendo falso.

Usualmente no hay código antes de su Exception que garantice que no se lanzará.

¿Por qué es bueno que Debug.Assert() se compile en prod? Si quieres saber sobre esto en la depuración, ¿no te gustaría saberlo en prod?

Lo quiere solo durante el desarrollo, porque una vez que encuentre Debug.Assert(false) situaciones Debug.Assert(false) , escriba el código para garantizar que Debug.Assert(false) no vuelva a suceder. Una vez hecho el desarrollo, suponiendo que ha encontrado las situaciones Debug.Assert(false) y las solucionó, Debug.Assert() se puede compilar de forma segura ya que ahora son redundantes.


EDITAR: En respuesta a la edición / nota que hizo en su publicación: Parece que usar excepciones es lo correcto para usar el uso de afirmaciones para el tipo de cosas que está tratando de lograr. Creo que el obstáculo mental que está afectando es que está considerando excepciones y afirmaciones para cumplir con el mismo propósito, y por lo tanto, está tratando de averiguar cuál de ellas sería ''correcto'' usar. Si bien puede haber cierta superposición en la forma en que se pueden usar las afirmaciones y las excepciones, no confundas que para ellos sean soluciones diferentes para el mismo problema; no lo son. Las afirmaciones y las excepciones tienen sus propios propósitos, fortalezas y debilidades.

Iba a escribir una respuesta con mis propias palabras, pero esto hace que el concepto sea mejor que el que tendría:

Estación C #: Afirmaciones

El uso de declaraciones de afirmación puede ser una forma efectiva de detectar errores de lógica de programa en tiempo de ejecución y, sin embargo, se filtra fácilmente fuera del código de producción. Una vez que se completa el desarrollo, el costo de tiempo de ejecución de estas pruebas redundantes para errores de codificación se puede eliminar simplemente definiendo el símbolo preprocesador NDEBUG [que deshabilita todas las aserciones] durante la compilación. Asegúrese, sin embargo, de recordar que el código colocado en la declaración se omitirá en la versión de producción.

Una aserción se utiliza mejor para probar una condición solo cuando se cumple todo lo siguiente:

* the condition should never be false if the code is correct, * the condition is not so trivial so as to obviously be always true, and * the condition is in some sense internal to a body of software.

Las afirmaciones casi nunca deberían usarse para detectar situaciones que surgen durante el funcionamiento normal del software. Por ejemplo, generalmente las aserciones no deben usarse para verificar errores en la entrada de un usuario. Sin embargo, puede tener sentido utilizar aserciones para verificar que un llamante ya haya verificado la entrada de un usuario.

Básicamente, use las excepciones para las cosas que deben capturarse / tratarse en una aplicación de producción, use las aserciones para realizar comprobaciones lógicas que serán útiles para el desarrollo pero que se desactivarán durante la producción.