Quiero usar la palabra clave Assert en mis aplicaciones de Android para destruir mi aplicación en algunos casos en el emulador o en mi dispositivo durante la prueba. es posible?
Parece que el emulador simplemente ignora mis afirmaciones.
Quiero usar la palabra clave Assert en mis aplicaciones de Android para destruir mi aplicación en algunos casos en el emulador o en mi dispositivo durante la prueba. es posible?
Parece que el emulador simplemente ignora mis afirmaciones.
Respuestas:
La API proporciona JUnit Assert .
Tu puedes hacer
import static junit.framework.Assert.*;
ahora puede utilizar todas las funciones como assertTrue, assertEquals, assertNull que se proporcionan en el marco junit.
Tenga cuidado de no importar el marco Junit4 a través de eclipse, ese sería el paquete org.junit. Tienes que usar el paquete junit.framework para que funcione en un dispositivo Android o en el emulador.
Consulte el documento Embedded VM Control (HTML sin formato del árbol de origen o una copia con un bonito formato ).
Básicamente, la VM Dalvik está configurada para ignorar las comprobaciones de aserción de forma predeterminada, aunque el código de bytes .dex incluye el código para realizar la comprobación. La verificación de aserciones se activa de dos formas:
(1) estableciendo la propiedad del sistema "debug.assert" a través de:
adb shell setprop debug.assert 1
que verifiqué funciona según lo previsto siempre que reinstale la aplicación después de hacer esto, o
(2) enviando el argumento de la línea de comandos "--enable-assert" a la VM dalvik, lo que podría no ser algo que los desarrolladores de aplicaciones puedan hacer (alguien me corrija si me equivoco aquí).
Básicamente, hay una bandera que se puede establecer de forma global, a nivel de paquete o a nivel de clase que habilita las afirmaciones en ese nivel respectivo. La bandera está desactivada de forma predeterminada, como resultado de lo cual se omiten las comprobaciones de aserción.
Escribí el siguiente código en mi actividad de muestra:
public class AssertActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
int x = 2 + 3;
assert x == 4;
}
}
Para este código, el código de bytes dalvik que se genera es (para Android 2.3.3):
// Static constructor for the class
000318: |[000318] com.example.asserttest.AssertActivity.:()V
000328: 1c00 0300 |0000: const-class v0, Lcom/example/asserttest/AssertActivity; // class@0003
00032c: 6e10 0c00 0000 |0002: invoke-virtual {v0}, Ljava/lang/Class;.desiredAssertionStatus:()Z // method@000c
000332: 0a00 |0005: move-result v0
000334: 3900 0600 |0006: if-nez v0, 000c // +0006
000338: 1210 |0008: const/4 v0, #int 1 // #1
00033a: 6a00 0000 |0009: sput-boolean v0, Lcom/example/asserttest/AssertActivity;.$assertionsDisabled:Z // field@0000
00033e: 0e00 |000b: return-void
000340: 1200 |000c: const/4 v0, #int 0 // #0
000342: 28fc |000d: goto 0009 // -0004
:
:
// onCreate()
00035c: |[00035c] com.example.asserttest.AssertActivity.onCreate:(Landroid/os/Bundle;)V
00036c: 6f20 0100 3200 |0000: invoke-super {v2, v3}, Landroid/app/Activity;.onCreate:(Landroid/os/Bundle;)V // method@0001
000372: 1501 037f |0003: const/high16 v1, #int 2130903040 // #7f03
000376: 6e20 0500 1200 |0005: invoke-virtual {v2, v1}, Lcom/example/asserttest/AssertActivity;.setContentView:(I)V // method@0005
00037c: 1250 |0008: const/4 v0, #int 5 // #5
00037e: 6301 0000 |0009: sget-boolean v1, Lcom/example/asserttest/AssertActivity;.$assertionsDisabled:Z // field@0000
000382: 3901 0b00 |000b: if-nez v1, 0016 // +000b
000386: 1251 |000d: const/4 v1, #int 5 // #5
000388: 3210 0800 |000e: if-eq v0, v1, 0016 // +0008
00038c: 2201 0c00 |0010: new-instance v1, Ljava/lang/AssertionError; // class@000c
000390: 7010 0b00 0100 |0012: invoke-direct {v1}, Ljava/lang/AssertionError;.:()V // method@000b
000396: 2701 |0015: throw v1
000398: 0e00 |0016: return-void
Observe cómo el constructor estático invoca el método desireAssertionStatus en el objeto Class y establece la variable de clase $ assertionsDisabled; También observe que en onCreate (), todo el código para lanzar java.lang.AssertionError está compilado, pero su ejecución depende del valor de $ assertionsDisabled que se establece para el objeto Class en el constructor estático.
Parece que la clase Assert de JUnit es lo que se usa predominantemente, por lo que es probable que sea una apuesta segura usarla. La flexibilidad de la palabra clave assert es la capacidad de activar las aserciones en el momento del desarrollo y desactivarlas para enviar bits y, en su lugar, fallar correctamente.
Espero que esto ayude.
import static junit.framework.Assert.*
y luego utilizo uno de sus métodos, como assertNotNull("It's null!", someObject);
, ¿esta afirmación está desactivada en los bits de envío?
adb shell setprop debug.assert 1
en Eclipse?
su
, luego setprop debug.assert 1
. Tenga en cuenta que el código que muestra desensamblado permanecerá en una versión de lanzamiento ( stackoverflow.com/a/5590378/506073 ). No creo que se le pueda decir al compilador javac que no emita aserciones, por lo que deben eliminarse de alguna manera. Una solución simple para eso es envolver la palabra clave assert en su propia función que proguard puede eliminar por usted.
Cuando las aserciones están habilitadas, la assert
palabra clave simplemente arroja un AssertionError
cuando la expresión booleana es false
.
Entonces, en mi opinión, la mejor alternativa, esp. si es reacio a depender de junit, es lanzar un AssertionError
explícitamente como se muestra a continuación:
assert x == 0 : "x = " + x;
Una alternativa a la declaración anterior es:
Utils._assert(x == 0, "x = " + x);
Donde el método se define como:
public static void _assert(boolean condition, String message) {
if (!condition) {
throw new AssertionError(message);
}
}
Los documentos de Oracle java recomiendan lanzar un AssertionError
como una alternativa aceptable.
Supongo que puede configurar Proguard para eliminar estas llamadas al código de producción.
En "Android en la práctica" se sugiere utilizar:
$adb shell setprop dalvik.vm.enableassertions all
Si esta configuración no persiste en su teléfono, puede crear un archivo /data/local.prop con propiedades como:
dalvik.vm.enableassertions=all
chmod 644
).
Me estaba fastidiando muchísimo, que mis afirmaciones no funcionaran, hasta que revisé el problema en Google ... Me di por vencido con las afirmaciones simples y usaré los métodos de aserción junits.
Por razones de conveniencia, estoy usando:
importar junit.framework.Assert estático. *;
Debido a la importación estática, luego puedo escribir:
asertTrue (...); en lugar de Assert.assertTrue (...);
Si está preocupado por el envío del código con el JUnit afirma en (o cualquier otra ruta de clase), puede usar la opción de configuración de ProGuard 'asumenosideeffects', que eliminará una ruta de clase en el supuesto de que eliminarla no afecta al código .
P.ej.
-assumenosideeffects junit.framework.Assert {
*;
}
Tengo una biblioteca de depuración común en la que coloco todos mis métodos de prueba y luego uso esta opción para eliminarla de mis aplicaciones publicadas.
Esto también elimina el problema difícil de detectar de la manipulación de cadenas que nunca se utilizan en el código de lanzamiento. Por ejemplo, si escribe un método de registro de depuración, y en ese método verifica el modo de depuración antes de registrar la cadena, todavía está construyendo la cadena, asignando memoria, llamando al método, pero luego optando por no hacer nada. Al eliminar la clase, se eliminan las llamadas por completo, es decir, siempre que su cadena se construya dentro de la llamada al método, también desaparece.
Sin embargo, asegúrese de que sea realmente seguro eliminar las líneas, ya que se hace sin verificación por parte de ProGuard. Eliminar cualquier método de devolución nulo estará bien, sin embargo, si está tomando valores de devolución de lo que esté eliminando, asegúrese de no usarlos para la lógica operativa real.
-assumenosideeffects class junit.framework.Assert { *; }
Puede usar aserciones, pero se necesita algo de trabajo para usarlas de manera confiable. La propiedad del sistema debug.assert
no es confiable; consulte los números 175697 , 65183 , 36786 y 17324 .
Un método es traducir cada assert
declaración a algo con lo que cualquier tiempo de ejecución pueda lidiar. Haga esto con un preprocesador de código fuente delante del compilador de Java. Por ejemplo, tome esta declaración:
assert x == 0: "Failure message";
Para una compilación de depuración, su preprocesador traduciría lo anterior en una if
declaración:
{ if( !(x == 0) ) throw new AssertionError( "Failure message" ); }
Para una construcción de producción, a una declaración vacía:
;
Tenga en cuenta que esto controlaría las afirmaciones en el momento de la compilación, a diferencia del tiempo de ejecución (la práctica habitual).
No pude encontrar un preprocesador listo para usar, así que escribí uno . Vea la parte que trata sobre las afirmaciones. La licencia para copiar está aquí .
Para agregar a la respuesta de Zulaxia sobre la eliminación de Junit: Proguard ya es parte de Android SDK / Eclipse y la siguiente página le indica cómo habilitarlo.
http://developer.android.com/guide/developing/tools/proguard.html
Además, lo anterior no funcionará con la última configuración predeterminada de proguard porque usa el indicador -dontoptimize que debe eliminarse y algunas de las optimizaciones activadas.
Utilice la palabra clave estándar de Java assert , por ejemplo:
assert a==b;
Para que esto funcione, debe agregar una línea a /system/build.prop y reiniciar el teléfono:
debug.assert=1
Esto funcionaría en un teléfono rooteado. Utilice algún administrador de archivos capaz de editar build.prop (por ejemplo, X-plore).
Ventajas: la mayoría (¿todos?) De los teléfonos Android se envían con las afirmaciones desactivadas. Incluso si su código afirma accidentalmente que es falso, la aplicación no interrumpirá ni fallará. Sin embargo, en su dispositivo de desarrollo obtendrá una excepción de aserción.