Android: Testes
Automatizados e TDD
Ivan de Aguirre
@IvAguirre
ivan.aguirre@dextra-sw.com
Agenda

• Conceitos e Terminologia.
• Overview do Framework de
testes.
• O que testar?
• TDD
Conceitos e Terminologia
Teste Unitário

•
•
•
•
•
•

Teste isolado de uma unidade do software.
Unidade precisa ser testável.
Uso de mocks, stubs e...
Teste Unitário

•
•
•
•
•
•

Teste isolado de uma unidade do software.
Unidade precisa ser testável.
Uso de mocks, stubs e...
•
•
•
•
•
•

Teste de API
Testes de endpoint.
Sistema integrado.
Asserções são mais difíceis.
Testes mais difíceis de mant...
Teste Funcional

• Black Box.
• Execução manual.
• É o que o tester faz.
•
•
•

Teste de UI
Simula uma execução de teste
funcional.
Difíceis de manter.
Execução lenta.
Testes Automatizados

• Integrados à build contínua.
• Feedback constante.
• Todos os testes devem estar
passando sempre.
...
Afinal, o que esperamos ao escrever
testes?
Afinal, o que esperamos ao escrever
testes?
Feedback
Afinal, o que esperamos ao escrever
testes?
Feedback

Qualidade
Afinal, o que esperamos ao escrever
testes?
Feedback

Evitar bugs

Qualidade
Afinal, o que esperamos ao escrever
testes?
Feedback

Evitar bugs

Qualidade

Agilidade
Afinal, o que esperamos ao escrever
testes?
Feedback

Qualidade

Confiança
Evitar bugs

Agilidade
Framework
Testes Unitários

• Classe base: AndroidTestCase
• Especializações:
o ApplicationTestCase
o LoaderTestCase
o ServiceTestCa...
public class AppProviderTestCase extends
ProviderTestCase2<DataProvider> {
private MockContentResolver mMockResolver;

	
	...
public void testInsertAndRetrieveQuestions2() {
Question q = new Question(1L, "Concorda ?");
q.addRecord(getMockContext())...
Testes com Instrumentação

• Classe base:
InstrumentationTestCase
• Especializações:
o ActivityTestCase
§ ActivityUnitTes...
public class QuestionActivityTestCase extends
ActivityUnitTestCase<QuestionActivity> {
...
public void testIntent() {
Inte...
public class MainActivityTestCase extends
ActivityInstrumentationTestCase2<MainActivity> {
	 public MainActivityTestCase()...
Instrumentation in =
getInstrumentation();

Ao trabalhar com eventos (click, touch, etc..) cuidado
com atrasos da Thread d...
•
•

Testes de UI
uiautomatorview (android_sdk/tools): detecta Views
acessíveis pelo automator e "NAF" nodes.
uiautomator:...
Que testes escrever?
O que disse Kent Beck?
I get paid for code that works, not for tests, so my
philosophy is to test as little as possible to reach a given
level of...
Different people will have different testing strategies based
on this philosophy, but that seems reasonable to me given
th...
Android Facts
Android Facts

•
•
•
•
•
•

Receitas de bolo ("boilerplate code").
Emulador é uma beleza. Só que não...
Certas classes do ...
Então: que testes escrever?

•
•
•

Você não precisa testar a API do Android.
Se necessário crie unidades testáveis fora d...
Dicas

• Classes difíceis de mockar: crie um
wrapper.
• Content Providers são fáceis de testar.
• Testes funcionais automa...
Dicas

• Testes de sanidade ajudam a evitar erros.
Ex.: apenas iniciar uma Activity.
• É possível testar execução "assíncr...
Exemplo: Sincronização
Authenticator.java
AuthenticatorService.java
SyncAdapter.java
SyncService.java
authenticator.xml
sy...
public class SyncAdapter extends
AbstractThreadedSyncAdapter{
...
	 @Override
	 public void onPerformSync(...) {
Código qu...
public class SyncAdapter extends
AbstractThreadedSyncAdapter{
...
	 @Override
	 public void onPerformSync(...) {
Código qu...
public class SyncAdapter extends
AbstractThreadedSyncAdapter{
...
	 @Override
	 public void onPerformSync(...) {
	
}
}
public class SyncAdapter extends
AbstractThreadedSyncAdapter{
...
	 @Override
	 public void onPerformSync(...) {
new Quest...
public class SyncAdapter extends
AbstractThreadedSyncAdapter{ é uma
QuestionSync
classe Java comum. É
...
mais fácil testá...
public class QuestionSyncTest

extends
ProviderTestCase2<DataProvider> {

...
public void testReceiveOneQuestionWhenDataBa...
private QuestionSync getSyncForWebServicesReturn(
final String wsReturn) {
	 final QuestionRemoteRepository mock = new
Que...
http://robolectric.org/
http://code.google.com/p/android-test-kit/
http://code.google.com/p/robotium/
http://bitbar.com/
TDD
while (true) {
Adicione um novo teste.
Faça o teste compilar.
Execute o teste: vai falhar !!
Implemente da forma mais
simp...
TDD - Sugestão de Workflow

•

Execução dos testes é muito lenta para
TDD de fato.

•

Crie unidades com TDD (ou algo pare...
Perguntas?
Muito Obrigado!
Ivan de Aguirre
@IvAguirre
ivan.aguirre@dextra-sw.com
Upcoming SlideShare
Loading in …5
×

Android: testes automatizados e TDD

2,478 views

Published on

Palestra ministrada por Ivan de Aguirre no AndoidDay 2013.

Published in: Technology

Android: testes automatizados e TDD

  1. 1. Android: Testes Automatizados e TDD Ivan de Aguirre @IvAguirre ivan.aguirre@dextra-sw.com
  2. 2. Agenda • Conceitos e Terminologia. • Overview do Framework de testes. • O que testar? • TDD
  3. 3. Conceitos e Terminologia
  4. 4. Teste Unitário • • • • • • Teste isolado de uma unidade do software. Unidade precisa ser testável. Uso de mocks, stubs e fakes. Execução rápida. Teste Unitário Clássico: unidade = classe. TDD: unidade = comportamento.
  5. 5. Teste Unitário • • • • • • Teste isolado de uma unidade do software. Unidade precisa ser testável. Uso de mocks, stubs e fakes. Execução rápida. Teste Unitário Clássico: unidade = classe. TDD: unidade = comportamento. You can't have unit tests if you don't have units. @CompSciFact
  6. 6. • • • • • • Teste de API Testes de endpoint. Sistema integrado. Asserções são mais difíceis. Testes mais difíceis de manter. Execução mais lenta. Ex.: método de uma classe de serviço, chamada à um webservice.
  7. 7. Teste Funcional • Black Box. • Execução manual. • É o que o tester faz.
  8. 8. • • • Teste de UI Simula uma execução de teste funcional. Difíceis de manter. Execução lenta.
  9. 9. Testes Automatizados • Integrados à build contínua. • Feedback constante. • Todos os testes devem estar passando sempre. Não elimina a necessidade de testes manuais.
  10. 10. Afinal, o que esperamos ao escrever testes?
  11. 11. Afinal, o que esperamos ao escrever testes? Feedback
  12. 12. Afinal, o que esperamos ao escrever testes? Feedback Qualidade
  13. 13. Afinal, o que esperamos ao escrever testes? Feedback Evitar bugs Qualidade
  14. 14. Afinal, o que esperamos ao escrever testes? Feedback Evitar bugs Qualidade Agilidade
  15. 15. Afinal, o que esperamos ao escrever testes? Feedback Qualidade Confiança Evitar bugs Agilidade
  16. 16. Framework
  17. 17. Testes Unitários • Classe base: AndroidTestCase • Especializações: o ApplicationTestCase o LoaderTestCase o ServiceTestCase o ProviderTestCase2
  18. 18. public class AppProviderTestCase extends ProviderTestCase2<DataProvider> { private MockContentResolver mMockResolver; public AppProviderTestCase() { super(DataProvider.class, Question.AUTHORITY); } @Override protected void setUp() throws Exception { super.setUp(); mMockResolver = getMockContentResolver(); }
  19. 19. public void testInsertAndRetrieveQuestions2() { Question q = new Question(1L, "Concorda ?"); q.addRecord(getMockContext()); Cursor c = mMockResolver.query( Question.CONTENT_URI, null, null, null, null); Question retrieved = new Question(c); assertEquals(1, c.getCount()); assertEquals(q.getId(), retrieved.getId()); assertEquals(q.getQuestionText(), retrieved.getQuestionText()); }
  20. 20. Testes com Instrumentação • Classe base: InstrumentationTestCase • Especializações: o ActivityTestCase § ActivityUnitTestCase (onCreate). § ActivityInstrumentationTestCase2 (ciclo completo).
  21. 21. public class QuestionActivityTestCase extends ActivityUnitTestCase<QuestionActivity> { ... public void testIntent() { Intent intent = new Intent(); String question = "Pergunta !!!"; intent.putExtra(Question.Columns.QUESTIONTEXT, question); Activity activity = startActivity(intent, null, null); TextView view = (TextView) activity.findViewById( R.id.question_text); assertEquals(question, view.getText()); } }
  22. 22. public class MainActivityTestCase extends ActivityInstrumentationTestCase2<MainActivity> { public MainActivityTestCase() { super(MainActivity.class); } public void testMainStarts() { assertNotNull("Activity nao foi criada!", getActivity()); } }
  23. 23. Instrumentation in = getInstrumentation(); Ao trabalhar com eventos (click, touch, etc..) cuidado com atrasos da Thread de UI.
  24. 24. • • Testes de UI uiautomatorview (android_sdk/tools): detecta Views acessíveis pelo automator e "NAF" nodes. uiautomator: o http://developer.android.com/tools/help/uiautomator/ index.html android:contentDescriptor: ImageButton, ImageView, CheckBox. o android:hint: EditText. o
  25. 25. Que testes escrever?
  26. 26. O que disse Kent Beck?
  27. 27. I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence (I suspect this level of confidence is high compared to industry standards, but that could just be hubris). If I don't typically make a kind of mistake (like setting the wrong variables in a constructor), I don't test for it. I do tend to make sense of test errors, so I'm extra careful when I have logic with complicated conditionals. When coding on a team, I modify my strategy to carefully test code that we, collectively, tend to get wrong.
  28. 28. Different people will have different testing strategies based on this philosophy, but that seems reasonable to me given the immature state of understanding of how tests can best fit into the inner loop of coding. Ten or twenty years from now we'll likely have a more universal theory of which tests to write, which tests not to write, and how to tell the difference. In the meantime, experimentation seems in order.
  29. 29. Android Facts
  30. 30. Android Facts • • • • • • Receitas de bolo ("boilerplate code"). Emulador é uma beleza. Só que não... Certas classes do framework são difíceis de mockar. Sistema externo pode complicar os testes. Asserções “visuais“ são díficeis de automatizar. Mesmo testes unitários demoram pra executar.
  31. 31. Então: que testes escrever? • • • Você não precisa testar a API do Android. Se necessário crie unidades testáveis fora dos componentes Android e isole o boilerplate code. Difícil de testar de forma automatizada: execução assíncrona, layouts, dependência de sistema remoto, dependência de outras aplicações, boilerplate code, reação à "condições adversas", etc.
  32. 32. Dicas • Classes difíceis de mockar: crie um wrapper. • Content Providers são fáceis de testar. • Testes funcionais automatizados podem ser difíceis de manter. • Testes difíceis de escrever ou de manter podem indicar um problema de design. • Instrumentação no lugar de testes de UI automatizados.
  33. 33. Dicas • Testes de sanidade ajudam a evitar erros. Ex.: apenas iniciar uma Activity. • É possível testar execução "assíncrona" de • forma unitária, por ex.: https:// android.googlesource.com/platform/ frameworks/base/+/master/test-runner/src/ android/test/LoaderTestCase.java Teste de Stress com Monkey:http:// developer.android.com/tools/help/ monkey.html
  34. 34. Exemplo: Sincronização Authenticator.java AuthenticatorService.java SyncAdapter.java SyncService.java authenticator.xml syncadapter.xml
  35. 35. public class SyncAdapter extends AbstractThreadedSyncAdapter{ ... @Override public void onPerformSync(...) { Código que faz a Sincronização } }
  36. 36. public class SyncAdapter extends AbstractThreadedSyncAdapter{ ... @Override public void onPerformSync(...) { Código que faz a Sincronização } } SyncAdapter é difícil de testar com testes unitários!!
  37. 37. public class SyncAdapter extends AbstractThreadedSyncAdapter{ ... @Override public void onPerformSync(...) { } }
  38. 38. public class SyncAdapter extends AbstractThreadedSyncAdapter{ ... @Override public void onPerformSync(...) { new QuestionSync(getContext()) .doSync(); } }
  39. 39. public class SyncAdapter extends AbstractThreadedSyncAdapter{ é uma QuestionSync classe Java comum. É ... mais fácil testá-la!! @Override public void onPerformSync(...) { new QuestionSync(getContext()) .doSync(); } }
  40. 40. public class QuestionSyncTest extends ProviderTestCase2<DataProvider> { ... public void testReceiveOneQuestionWhenDataBaseIsEmpty() { Cursor c = mMockResolver.query(Question.CONTENT_URI, null, null, null, null); assertEquals(0, c.getCount()); String json = "[{"id":1, "question": "nova pergunta"}]"; getSyncForWebServicesReturn(json).doSync(); c = mMockResolver.query(Question.CONTENT_URI, null, null, null, null); assertEquals(1, c.getCount()); } }
  41. 41. private QuestionSync getSyncForWebServicesReturn( final String wsReturn) { final QuestionRemoteRepository mock = new QuestionRemoteRepository() { @Override protected String fetchAll() { return wsReturn; } }; return new QuestionSync(getMockContext()) { @Override public void doSync() { this.questionsRepository = mock; super.doSync(); } };
  42. 42. http://robolectric.org/ http://code.google.com/p/android-test-kit/ http://code.google.com/p/robotium/ http://bitbar.com/
  43. 43. TDD
  44. 44. while (true) { Adicione um novo teste. Faça o teste compilar. Execute o teste: vai falhar !! Implemente da forma mais simples possível para o teste passar. Refatore e mantenha os testes verdes. }
  45. 45. TDD - Sugestão de Workflow • Execução dos testes é muito lenta para TDD de fato. • Crie unidades com TDD (ou algo parecido com isso). • Depois de alguma iterações adicione componentes Android.
  46. 46. Perguntas?
  47. 47. Muito Obrigado! Ivan de Aguirre @IvAguirre ivan.aguirre@dextra-sw.com

×