Quero usar a palavra-chave Assert em meus aplicativos Android para destruir meu aplicativo em alguns casos no emulador ou meu dispositivo durante o teste. Isso é possível?
Parece que o emulador simplesmente ignora minhas afirmações.
Quero usar a palavra-chave Assert em meus aplicativos Android para destruir meu aplicativo em alguns casos no emulador ou meu dispositivo durante o teste. Isso é possível?
Parece que o emulador simplesmente ignora minhas afirmações.
Respostas:
A API fornece o JUnit Assert .
Você pode fazer
import static junit.framework.Assert.*;
agora você pode usar todas as funções como assertTrue, assertEquals, assertNull que são fornecidas na estrutura junit.
Tenha cuidado para não importar a estrutura Junit4 por meio do eclipse, que seria o pacote org.junit. Você precisa usar o pacote junit.framework para fazê-lo funcionar em um dispositivo Android ou emulador.
Consulte o documento Embedded VM Control (HTML bruto da árvore de origem ou uma cópia bem formatada ).
Basicamente, a VM Dalvik é configurada para ignorar as verificações de asserção por padrão, embora o código de byte .dex inclua o código para realizar a verificação. A verificação de asserções é ativada de duas maneiras:
(1) definindo a propriedade do sistema "debug.assert" via:
adb shell setprop debug.assert 1
que verifiquei funcionar conforme o esperado, contanto que você reinstale seu aplicativo depois de fazer isso, ou
(2) enviando o argumento de linha de comando "--enable-assert" para a VM dalvik, que pode não ser algo que os desenvolvedores de aplicativos sejam capazes de fazer (alguém me corrija se eu estiver errado aqui).
Basicamente, há um sinalizador que pode ser definido globalmente, em um nível de pacote ou em um nível de classe que permite asserções naquele respectivo nível. O sinalizador está desativado por padrão, como resultado do qual as verificações de asserção são ignoradas.
Escrevi o seguinte código em minha atividade de amostra:
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, o código de bytes dalvik gerado é (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 como o construtor estático invoca o método neededAssertionStatus no objeto Class e define a variável de classe $ assertionsDisabled; também observe que em onCreate (), todo o código para lançar java.lang.AssertionError é compilado, mas sua execução depende do valor de $ assertionsDisabled que é definido para o objeto Class no construtor estático.
Parece que a classe Assert do JUnit é a que é usada predominantemente, então é provável que seja uma aposta segura usá-la. A flexibilidade da palavra-chave assert é a capacidade de ativar assertions no tempo de desenvolvimento e desativá-los para enviar bits e, em vez disso, falhar normalmente.
Espero que isto ajude.
import static junit.framework.Assert.*
e depois usar um de seus métodos, como assertNotNull("It's null!", someObject);
, essa afirmação está desativada em bits de envio?
adb shell setprop debug.assert 1
no Eclipse?
su
Então, primeiro setprop debug.assert 1
. Observe que o código que você mostra desmontado permanecerá em uma versão de compilação ( stackoverflow.com/a/5590378/506073 ). Não acredito que o compilador javac possa ser instruído a não emitir asserções, portanto, elas precisam ser eliminadas de alguma forma. Uma solução simples para isso é envolver a palavra-chave assert em sua própria função que o proguard pode remover para você.
Quando as asserções estão habilitadas, a assert
palavra - chave simplesmente lança um AssertionError
quando a expressão booleana é false
.
Então, IMO, a melhor alternativa, esp. se você é avesso a depender de junit, é lançar um AssertionError
explicitamente como mostrado abaixo:
assert x == 0 : "x = " + x;
Uma alternativa para a declaração acima é:
Utils._assert(x == 0, "x = " + x);
Onde o método é definido como:
public static void _assert(boolean condition, String message) {
if (!condition) {
throw new AssertionError(message);
}
}
Os documentos do Oracle Java recomendam lançar um AssertionError
como alternativa aceitável.
Eu acho que você pode configurar o Proguard para eliminar essas chamadas de código de produção.
Em "Android na prática", sugere-se o uso de:
$adb shell setprop dalvik.vm.enableassertions all
se essas configurações não persistirem em seu telefone, você pode criar o arquivo /data/local.prop com propriedades como:
dalvik.vm.enableassertions=all
chmod 644
).
Estava me incomodando muito, que minhas afirmações não funcionassem, até que verifiquei o problema no google ... Desisti das afirmações simples e irei com os métodos de asserção junits.
Para fins de conveniência, estou usando:
import static junit.framework.Assert. *;
Devido à importação estática, posso escrever mais tarde:
assertTrue (...); em vez de Assert.assertTrue (...);
Se você estiver preocupado com o envio de código com o JUnit asserts in (ou qualquer outro caminho de classe), você pode usar a opção de configuração do ProGuard 'assumenosideeffects', que removerá um caminho de classe na suposição de que removê-lo não afeta o código .
Por exemplo.
-assumenosideeffects junit.framework.Assert {
*;
}
Eu tenho uma biblioteca de depuração comum onde coloquei todos os meus métodos de teste e, em seguida, uso esta opção para retirá-la dos meus aplicativos lançados.
Isso também elimina o problema de difícil localização de cadeias de caracteres manipuladas que nunca são usadas no código de lançamento. Por exemplo, se você escrever um método de log de depuração e, nesse método, verificar o modo de depuração antes de registrar a string, ainda estará construindo a string, alocando memória, chamando o método, mas optando por não fazer nada. Remover a classe remove as chamadas inteiramente, o que significa que, desde que sua string seja construída dentro da chamada do método, ela também desaparecerá.
No entanto, certifique-se de que é genuinamente seguro apenas remover as linhas, pois isso é feito sem verificação por parte do ProGuard. A remoção de qualquer método de retorno nulo será suficiente, no entanto, se você estiver obtendo quaisquer valores de retorno de tudo o que está removendo, certifique-se de não usá-los para a lógica operacional real.
-assumenosideeffects class junit.framework.Assert { *; }
Você pode usar asserções, mas dá algum trabalho usá-las de maneira confiável. A propriedade do sistema debug.assert
não é confiável; veja os problemas 175697 , 65183 , 36786 e 17324 .
Um método é traduzir cada assert
instrução em algo com que qualquer tempo de execução possa lidar. Faça isso com um pré-processador de origem na frente do compilador Java. Por exemplo, veja esta declaração:
assert x == 0: "Failure message";
Para uma compilação de depuração, seu pré-processador traduziria o acima em uma if
instrução:
{ if( !(x == 0) ) throw new AssertionError( "Failure message" ); }
Para uma construção de produção, para uma instrução vazia:
;
Observe que isso controlaria as asserções no tempo de construção, ao contrário do tempo de execução (a prática usual).
Não consegui encontrar nenhum pré-processador pronto, então criei um . Veja a parte que trata das afirmações. Licença para copiar é aqui .
Para adicionar à resposta da Zulaxia sobre eliminar o Junit - Proguard já faz parte do Android SDK / Eclipse e a página a seguir mostra como habilitá-lo.
http://developer.android.com/guide/developing/tools/proguard.html
Além disso, o acima não funcionará com a configuração do programa padrão mais recente porque usa o sinalizador -dontoptimize que deve ser retirado e algumas das otimizações ativadas.
Use a palavra-chave assert Java padrão , por exemplo:
assert a==b;
Para que isso funcione, você deve adicionar uma linha a /system/build.prop e reiniciar o telefone:
debug.assert=1
Isso funcionaria no telefone enraizado. Use algum gerenciador de arquivos capaz de editar build.prop (por exemplo, X-plore).
Vantagens: a maioria (todos?) Dos telefones Android são fornecidos com as declarações desativadas. Mesmo que seu código seja acidentalmente declarado falso, o aplicativo não interrompe ou falha. No entanto, em seu dispositivo de desenvolvimento, você obterá exceção de asserção.