android: testes automatizados e tdd
DESCRIPTION
Palestra ministrada por Ivan de Aguirre no AndoidDay 2013.TRANSCRIPT
![Page 1: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/1.jpg)
Android: Testes Automatizados e TDD
Ivan de Aguirre@IvAguirre
![Page 2: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/2.jpg)
Agenda
• Conceitos e Terminologia.• Overview do Framework de
testes.• O que testar?• TDD
![Page 3: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/3.jpg)
Conceitos e Terminologia
![Page 4: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/4.jpg)
• 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.
Teste Unitário
![Page 5: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/5.jpg)
• 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.
Teste Unitário
You can't have unit tests if you don't have units.@CompSciFact
![Page 6: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/6.jpg)
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.
![Page 7: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/7.jpg)
• Black Box.• Execução manual.• É o que o tester faz.
Teste Funcional
![Page 8: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/8.jpg)
Teste de UI• Simula uma execução de teste
funcional.• Difíceis de manter.• Execução lenta.
![Page 9: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/9.jpg)
Testes Automatizados
• Integrados à build contínua.• Feedback constante.• Todos os testes devem estar
passando sempre.
Não elimina a necessidade de testes manuais.
![Page 10: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/10.jpg)
Afinal, o que esperamos ao escrever testes?
![Page 11: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/11.jpg)
Afinal, o que esperamos ao escrever testes?
Feedback
![Page 12: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/12.jpg)
Afinal, o que esperamos ao escrever testes?
QualidadeFeedback
![Page 13: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/13.jpg)
Afinal, o que esperamos ao escrever testes?
QualidadeFeedback
Evitar bugs
![Page 14: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/14.jpg)
Afinal, o que esperamos ao escrever testes?
QualidadeFeedback
Evitar bugs Agilidade
![Page 15: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/15.jpg)
Afinal, o que esperamos ao escrever testes?
QualidadeFeedback
Evitar bugs
Confiança
Agilidade
![Page 16: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/16.jpg)
Framework
![Page 17: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/17.jpg)
• Classe base: AndroidTestCase• Especializações:o ApplicationTestCaseo LoaderTestCaseo ServiceTestCaseo ProviderTestCase2
Testes Unitários
![Page 18: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/18.jpg)
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(); }
![Page 19: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/19.jpg)
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());}
![Page 20: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/20.jpg)
• Classe base: InstrumentationTestCase
• Especializações:o ActivityTestCase
§ ActivityUnitTestCase (onCreate).§ ActivityInstrumentationTestCase2
(ciclo completo).
Testes com Instrumentação
![Page 21: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/21.jpg)
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()); }}
![Page 22: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/22.jpg)
public class MainActivityTestCase extendsActivityInstrumentationTestCase2<MainActivity> {
public MainActivityTestCase() { super(MainActivity.class); }
public void testMainStarts() { assertNotNull("Activity nao foi criada!", getActivity()); }}
![Page 23: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/23.jpg)
Instrumentation in = getInstrumentation();
Ao trabalhar com eventos (click, touch, etc..) cuidado com atrasos da Thread de UI.
![Page 24: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/24.jpg)
• uiautomatorview (android_sdk/tools): detecta Views acessíveis pelo automator e "NAF" nodes.
• uiautomator:o http://developer.android.com/tools/help/uiautomator/
index.htmlo android:contentDescriptor:
ImageButton, ImageView, CheckBox.
o android:hint: EditText.
Testes de UI
![Page 25: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/25.jpg)
Que testes escrever?
![Page 26: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/26.jpg)
O que disse Kent Beck?
![Page 27: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/27.jpg)
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.
![Page 28: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/28.jpg)
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.
![Page 29: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/29.jpg)
Android Facts
![Page 30: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/30.jpg)
• 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.
Android Facts
![Page 31: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/31.jpg)
• 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.
Então: que testes escrever?
![Page 32: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/32.jpg)
• 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.
Dicas
![Page 33: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/33.jpg)
• 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
Dicas
![Page 34: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/34.jpg)
Exemplo: SincronizaçãoAuthenticator.javaAuthenticatorService.javaSyncAdapter.javaSyncService.javaauthenticator.xmlsyncadapter.xml
![Page 35: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/35.jpg)
public class SyncAdapter extends AbstractThreadedSyncAdapter{ ... @Override public void onPerformSync(...) {
}}
Código que faz a Sincronização
![Page 36: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/36.jpg)
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!!
![Page 37: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/37.jpg)
public class SyncAdapter extends AbstractThreadedSyncAdapter{ ... @Override public void onPerformSync(...) {
}}
![Page 38: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/38.jpg)
public class SyncAdapter extends AbstractThreadedSyncAdapter{ ... @Override public void onPerformSync(...) {
}}
new QuestionSync(getContext()) .doSync();
![Page 39: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/39.jpg)
public class SyncAdapter extends AbstractThreadedSyncAdapter{ ... @Override public void onPerformSync(...) {
}}
new QuestionSync(getContext()) .doSync();
QuestionSync é uma classe Java comum. É mais fácil testá-la!!
![Page 40: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/40.jpg)
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()); }}
![Page 41: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/41.jpg)
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(); } };}
![Page 42: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/42.jpg)
http://robolectric.org/
http://code.google.com/p/android-test-kit/
http://code.google.com/p/robotium/
http://bitbar.com/
![Page 43: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/43.jpg)
TDD
![Page 44: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/44.jpg)
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. }
![Page 45: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/45.jpg)
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.
![Page 46: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/46.jpg)
Perguntas?
![Page 47: Android: testes automatizados e TDD](https://reader033.vdocuments.us/reader033/viewer/2022042700/5590b1041a28abea058b4635/html5/thumbnails/47.jpg)
Muito Obrigado!
Ivan de Aguirre@IvAguirre