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.
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.
Bem, o OP pediu “palavra-chave assert” que - ao contrário de junit.framework.Assert pode ser otimizada pelo JIT. E por isso mesmo vim aqui. Espero que algumas das outras respostas sejam mais úteis.
Martin
27
Eu odeio ser rude, mas essa não deve ser a resposta aceita porque não responde à pergunta (concordo com o comentário de @Martin). Outras respostas explicam como fazer a palavra-chave assert funcionar corretamente, por exemplo, execute "adb shell setprop debug.assert 1"
jfritz42
3
Votos negados porque OP perguntou sobre a palavra-chave assert. @scorpiodawg descreveu o processo abaixo: stackoverflow.com/a/5563637/484261
A resposta de scorpiodawg veio apenas um ano depois, então acho que essa resposta foi aceita apenas porque o OP, por algum motivo, se sentiu obrigado a marcar uma resposta como aceita. Essa atitude torna um grande número de respostas no SO incompletas ou completamente terríveis.
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.assert1
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:
publicclassAssertActivityextendsActivity{@Overrideprotectedvoid 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):
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.
Parece que o Google removeu a fonte navegável (vi referências a isso em respostas a outras perguntas aqui). Sua melhor aposta é obter a fonte ou tentar pesquisá-la em um mecanismo de busca. Procure por "dalvik / embedded-vm-control.html". Aqui está um lugar que o contém: assembla.com/code/android-gb-for-sharp-is01/git/nodes/dalvik/… . Espero que isto ajude.
scorpiodawg
Muito útil, obrigado. Estou confuso com a distinção feita no penúltimo parágrafo, no entanto. Estamos discutindo dois tipos de assertivas: o primeiro sendo os métodos do pacote JUnit Assert como assertNotNull (), e o segundo sendo a palavra-chave 'assert' da linguagem Java. Sua resposta se aplica a ambos? Por exemplo, se eu 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?
Jeffro
1
Olá, Jeffro, não acredito - junit.framework.Assert é simplesmente uma classe que lança uma exceção quando a condição de entrada é considerada falsa. A palavra-chave assert, por outro lado, está incorporada ao idioma. Espero que isto ajude.
scorpiodawg
3
Existe uma maneira de fazer adb shell setprop debug.assert 1no Eclipse?
Pacerier
1
Asserções também podem ser feitas a partir de um terminal em execução no dispositivo se você for root. suEntã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ê.
ahcox
10
Quando as asserções estão habilitadas, a assertpalavra - chave simplesmente lança um AssertionErrorquando a expressão booleana é false.
Então, IMO, a melhor alternativa, esp. se você é avesso a depender de junit, é lançar um AssertionErrorexplicitamente como mostrado abaixo:
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.
Acho que a sintaxe adequada seria:-assumenosideeffects class junit.framework.Assert { *; }
Pooks
Resposta confusa. O comando mencionado causa um erro de proguard. O comando corrigido pelo Pooks ainda não remove as asserções do arquivo dex binário.
Pointer Null
Eu tenho o mesmo problema @PointerNull. afirmar não será removido.
Mahdi
3
Você pode usar asserções, mas dá algum trabalho usá-las de maneira confiável. A propriedade do sistema debug.assertnão é confiável; veja os problemas 175697 , 65183 , 36786 e 17324 .
Um método é traduzir cada assertinstruçã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 ifinstrução:
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.
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.
Respostas:
A API fornece o JUnit Assert .
Você pode fazer
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.
fonte
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:
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:
Para este código, o código de bytes dalvik gerado é (para Android 2.3.3):
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.
fonte
import static junit.framework.Assert.*
e depois usar um de seus métodos, comoassertNotNull("It's null!", someObject);
, essa afirmação está desativada em bits de envio?adb shell setprop debug.assert 1
no Eclipse?su
Então, primeirosetprop 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 umAssertionError
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:Uma alternativa para a declaração acima é:
Onde o método é definido como:
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.
fonte
Em "Android na prática", sugere-se o uso de:
se essas configurações não persistirem em seu telefone, você pode criar o arquivo /data/local.prop com propriedades como:
fonte
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 (...);
fonte
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.
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.
fonte
-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:Para uma compilação de depuração, seu pré-processador traduziria o acima em uma
if
instrução: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 .
fonte
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.
fonte
Use a palavra-chave assert Java padrão , por exemplo:
Para que isso funcione, você deve adicionar uma linha a /system/build.prop e reiniciar o telefone:
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.
fonte