how java language-agnostic assert

how - assert java selenium



Algunos(anti-) patrones en el uso de assert(Java y otros) (4)

Recomiendo verificar los parámetros en los métodos públicos (API) y lanzando IllegalArgumentException si los params no son válidos. No hay afirmaciones aquí, ya que un usuario de la API necesita obtener un mensaje de error (mensaje) adecuado.

Los asertos se deben usar en métodos no públicos para verificar las condiciones posteriores y posiblemente las precondiciones. Por ejemplo:

List returnListOfSize(int size) { // complex list creation assert list.size == size; }

A menudo, se puede eludir el uso de una estrategia de manejo inteligente de errores.

Finalmente, tengo una pregunta que hacer sobre Stack Overflow. :-)

El objetivo principal es Java, pero creo que es en su mayoría agnóstico del lenguaje: si no tienes assert nativo, siempre puedes simularlo.

Trabajo para una compañía que vende un conjunto de programas escritos en Java. El código es antiguo, se remonta a Java 1.3 al menos, y en algunos lugares, muestra ... Esa es una gran base de código, unos 2 millones de líneas, por lo que no podemos refactorizar todo de una vez.
Recientemente, cambiamos las últimas versiones de la sintaxis de Java 1.4 y JVM a Java 1.6, haciendo un uso conservador de algunas características nuevas como assert (utilizamos una macro DEBUG.ASSERT - Sé que assert se introdujo en 1.4 pero no lo hicimos lo usé antes), genéricos (solo colecciones tipeadas), foreach loop, enums, etc.

Todavía estoy un poco verde sobre el uso de assert, aunque he leído un par de artículos sobre el tema. Sin embargo, algunos usos que veo me dejan perplejo, dañando mi sentido común ... ^ _ ^ Así que pensé que debería hacer algunas preguntas, para ver si estoy en lo cierto al querer corregir las cosas, o si va en contra de las prácticas comunes. Soy parlanchín, así que hice las preguntas en negrita , para aquellos que les gusta descremada.

Como referencia, he buscado assert java en SO y he encontrado algunos hilos interesantes, pero aparentemente no hay duplicados exactos.

Primero, el problema principal, que activó mi pregunta hoy:

SubDocument aSubDoc = documents.GetAt( i ); assert( aSubDoc != null ); if ( aSubDoc.GetType() == GIS_DOC ) { continue; } assert( aSubDoc.GetDoc() != null ); ContentsInfo ci = (ContentsInfo) aSubDoc.GetDoc();

( Sí, usamos las convenciones de estilo / código de MS C / C ++. ¡Y hasta me gusta (viniendo del mismo fondo)!
Primero, el formulario assert() proviene de la conversión de llamadas DEBUG.ASSERT() . No me gustan los paréntesis adicionales, ya que assert es una construcción de lenguaje, no (ya no, aquí) una llamada de función. No me gusta también return (foo); :-)
A continuación, las afirmaciones no prueban aquí para invariantes, sino que se usan como protectores contra los valores incorrectos. Pero según lo entiendo, son inútiles aquí: el assert arrojará una excepción, ni siquiera documentada con una cadena complementaria, y solo si las aserciones están habilitadas. Entonces, si tenemos la opción -ea , simplemente tenemos una afirmación lanzada en lugar de la habitual NullPointerException. Eso no parece una ventaja primordial, ya que de todos modos capturamos excepciones sin marcar al más alto nivel.
¿Estoy en lo cierto al suponer que podemos deshacernos de ellos y vivir con eso (es decir, dejar que Java eleve esa excepción sin ataduras)? (o, por supuesto, prueba contra valor nulo si es posible, lo cual se hace en otros lugares).

Nota al margen: si tuviera que afirmar en el fragmento anterior, lo haría contra el valor ci, no contra el getter: incluso si la mayoría de los getters están optimizados / en línea, no podemos estar seguros, por lo que deberíamos evitar llamarlo dos veces.

Alguien dijo, en el último hilo de referencia, que los métodos públicos deberían usar pruebas contra los valores de los parámetros (uso de la API pública) y que los métodos privados deberían basarse en los asertos. Buen consejo.
Ahora, ambos tipos de métodos deben verificar otra fuente de datos: entrada externa. Es decir. datos provenientes del usuario, de una base de datos, de algún archivo o de la red, por ejemplo.
En nuestro código, veo argumentos en contra de estos valores. Siempre los cambio a una prueba real, por lo que actúan incluso con aserciones desactivadas: no son invariantes y deben manejarse adecuadamente.
Solo veo una posible excepción, donde la entrada se supone constante, por ejemplo, una tabla de base de datos llena de constantes utilizadas en las relaciones: el programa se rompería si se cambia esta tabla, pero el código correspondiente no se actualizó.
¿Ves otras excepciones?

Otro uso relativamente frecuente que veo, que parece estar bien: en el valor predeterminado de un cambio, o al final de una serie de else if prueban todos los valores posibles (¡estos casos datan de antes del uso de enumeraciones!), A menudo hay una assert false : "Unexpected value for stuff: " + stuff;
Parece legítimo para mí (estos casos no deberían ocurrir en producción), ¿qué piensas? (más allá de los consejos "sin interruptor, use OO" que son irrelevantes aquí).

Y, por último, ¿hay algún otro caso de uso útil o errores molestos que he omitido aquí? (¡probablemente!)


Uso assert , no solo para la validación de parámetros, sino también para verificar Threads. Cada vez que hago swing, escribo assert en casi todos los métodos para marcar "Solo debería ejecutar en thread worker / AWTThread". (Creo que Sun debería hacerlo por nosotros.) Debido al modelo de subprocesamiento Swing, NO PUEDE fallar (y fallar aleatoriamente) si accede a la API móvil desde un subproceso no relacionado con la interfaz de usuario. Es bastante difícil descubrir todos estos problemas sin afirmar.

Otro ejemplo que puedo imaginar es verificar el recurso incluido JAR. Puedes tener una excepción en inglés en lugar de NPE.

EDITAR: Otro ejemplo; control de bloqueo de objetos Si sé que voy a usar un bloque sincronizado anidado, o si voy a arreglar un punto muerto, uso Thread.holdLock (Object) para asegurarme de que no obtendré los bloqueos en orden inverso.

EDITAR (2): si está seguro de que nunca se alcanzará algún bloque de código, puede escribir

throw new AssertionError("You dead");

en lugar

assert false:"I am lucky";

Por ejemplo, si reemplaza "equal (Object)" en un objeto mutable, anule hashCode () con AssertionError si cree que nunca será la clave. Esta práctica se sugiere en algunos libros. No voy a perjudicar el rendimiento (como nunca debería llegar).


usted ha mencionado muchas de las razones por las que creo que las afirmaciones deberían evitarse en general. a menos que trabaje con una base de código donde el uso afirmativo tenga pautas muy estrictas, rápidamente se encuentra en una situación en la que no puede apagar las afirmaciones, en cuyo caso también podría estar utilizando pruebas lógicas normales.

entonces, mi recomendación es omitir las aserciones. no se meta en las comprobaciones de puntero nulo donde el idioma lo hará por usted. sin embargo, si el puntero no puede desreferenciarse durante un tiempo, la verificación nula anticipada es una buena idea. también, siempre use excepciones reales para casos que "nunca" deberían suceder (la rama final si o la caja de switch predeterminada), no use "assert false". si usa una afirmación, existe la posibilidad de que alguien la apague, y si la situación realmente sucede, las cosas se pondrán realmente confusas.


La regla número uno es evitar los efectos secundarios en las afirmaciones. En otras palabras, el código debe comportarse de manera idéntica con las aserciones desactivadas como cuando las aserciones están activadas y no fallan (obviamente las aserciones que fallan van a alterar el comportamiento porque generarán un error).

La regla número dos es no usar aserciones para verificaciones esenciales. Se pueden apagar (o, más correctamente, no encender). Para la verificación de parámetros de métodos no privados, use IllegalArgumentException.

Las aserciones son suposiciones ejecutables. Uso aserciones para expresar mis creencias sobre el estado actual del programa. Por ejemplo, cosas como "supongo que n es positivo aquí" , o "supongo que la lista tiene precisamente un elemento aquí" .