O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

TDC2016POA | Trilha Android - Testes no Android

171 visualizações

Publicada em

Testes no Android

Publicada em: Educação
  • Seja o primeiro a comentar

TDC2016POA | Trilha Android - Testes no Android

  1. 1. Conceitos, práticas e motivações Testes no Android
  2. 2. Eu Chapter Lead de Android www.rafaeltoledo.net twitter.com/_rafaeltoledo github.com/rafaeltoledo blog.concretesolutions.com.br
  3. 3. Por que escrever Testes? o dilema do programador mobile
  4. 4. Garantir que algo funciona da forma como deveria Documentação de comportamento de um sistema Garantir que uma mudança não quebra outras partes do app
  5. 5. A pirâmide refere-se ao desenvolvimento backend Front-end em si é interface (GUI) Ao contrário dos apps 100% offline, se muitas regras de negócio concentram-se no front-end, é sinal que sua arquitetura está errada
  6. 6. Por que tenho 2 pastas de Testes? o que são as pastas test e androidTest no meu projeto?
  7. 7. Testes unitários / funcionais instrumentados, que necessitam das classes do Android para a execução. São executados em emuladores ou devices reais androidTest
  8. 8. Testes unitários executados na JVM (máquina local) Componentes externos geralmente são mockados (como as classes do Android)* test
  9. 9. Testes unitários executados na JVM (máquina local) Componentes externos geralmente são mockados (como as classes do Android)* Robolectric
  10. 10. escopos de dependências // somente test testCompile 'junit:junit:4.12' testCompile 'org.robolectric:robolectric:3.1.2' // somente androidTest androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test:rules:0.5'
  11. 11. Bibliotecas e Frameworks quem poderá nos ajudar?
  12. 12. Framework para criação de testes ‘repetíveis’ Estrutura da execução dos testes Biblioteca de asserções public class MeuTeste { @Test public void stuffTest() { Assert.assertEquals(2, 1 + 1); } }
  13. 13. Biblioteca para a criação de asserções mais intuitivas e legíveis Se tornou parte do JUnit assertThat(1 + 1, is(2)); assertThat(lista, contains(2, 3, 4, 8); String texto = "Android no TDC" assertThat(texto, containsString("Android"); assertThat(texto, not(containsString("iOS"); Hamcrest
  14. 14. Biblioteca para a criação de asserções mais intuitivas, legíveis e fluentes Possui uma extensão chamada AssertJ Android feita pela Square assertThat(sociedadeDoAnel) .hasSize(9) .contains(frodo, sam) .doesNotContain(sauron); // AssertJ Android assertThat(view).isGone(); AssertJ
  15. 15. Biblioteca para a criação de mocks List mockedList = mock(List.class); mockedList.add("one"); mockedList.clear(); verify(mockedList).add("one"); verify(mockedList).clear();
  16. 16. LinkedList mockedList = mock(LinkedList.class); when(mockedList.get(0)).thenReturn("first"); // Vai mostrar "first" System.out.println(mockedList.get(0)); // Vai mostrar null, já que não mockamos o comportamento System.out.println(mockedList.get(999));
  17. 17. Framework para a criação de testes Instrumentados no Android Espresso AndroidJUnitRunner JUnit4 Rules UI Automator Android Testing Support Library
  18. 18. Espresso Biblioteca para a escrita de testes unitários de UI para o Android onView(withId(R.id.name_field)).perform(typeText("TDC")); onView(withId(R.id.greet_button)).perform(click()); onView(withText("Olá, TDC!")).check(matches(isDisplayed()); Android Testing Support Library
  19. 19. AndroidJUnitRunner Suporte ao JUnit 4, acesso a informações da instrumentação (contexto, execução, etc.), filtro de testes e distribuição Rules Possibilita testar Activity, Intent e Service UiAutomator Testes de UI no Android de forma “livre” Android Testing Support Library
  20. 20. “Robolectric é um framework de testes unitários que desacopla a dependência do jar do Android, de forma que você possa fazer o desenvolvimento do seu aplicativo guiado por testes. Execute seus testes na JVM em segundos!” É um simulador do ambiente de execução do Android Testes são “instrumentados” na própria JVM Robolectric
  21. 21. @Test public void clickingButton_shouldChangeResultsViewText() { MyActivity activity = Robolectric.setupActivity(MyActivity.class); Button button = (Button) activity.findViewById(R.id.button); TextView results = (TextView) activity.findViewById(R.id.results); button.performClick(); assertThat(results.getText().toString()).isEqualTo("Hello!"); } Robolectric
  22. 22. Request Matcher Biblioteca open-source para a criação de asserções das requests do app, utilizando em conjunto o Mock Web Server da Square serverRule.enqueue(200, "body.json") .assertPathIs("/somepath") .assertNoBody() .assertMethodIs(RequestMatcher.GET); github.com/concretesolutions/requestmatcher
  23. 23. Organização dos testes porque teste também é código
  24. 24. Organização AAA Arrange (Organizar): set-up dos testes, preparação dos objetos, etc. Act (Agir): a execução, ou o exercício do comportamento propriamente dito Assert (Confirmação): a verificação se o resultado da execução foi o esperado
  25. 25. Organização OCA Organizar: set-up dos testes, preparação dos objetos, etc. Agir: a execução, ou o exercício do comportamento propriamente dito Confirmação: a verificação se o resultado da execução foi o esperado
  26. 26. Organização OCA // O Calculator c = new Calculator(); c.setFirstNumber(1); c.setSecondNumber(2); c.setOperation(Calculador.SUM); // C c.performOperation(); // A assertThat(c.getResult(), is(3));
  27. 27. Código difícil de testar testes podem denunciar problemas no design de classes
  28. 28. Design de classes Calculator c = new Calculator(); c.setFirstNumber(1); c.setSecondNumber(2); c.setOperation(Calculador.SUM); c.performOperation(); assertThat(c.getResult(), is(3));
  29. 29. Design de classes Calculator c = new Calculator.Builder() .firstNumber(1) .secondNumber(2) .operation(Calculador.SUM) .build(); c.performOperation(); assertThat(c.getResult(), is(3));
  30. 30. Por onde começar? ok, conheço as ferramentas... mas o que eu testo?
  31. 31. Nossa cobaia será um app que consome a API do StackOverflow e lista os usuários com a maior reputação no site
  32. 32. Consumo de API com Retrofit RecyclerView com endless scroll Salvando dados na mudança de orientação!
  33. 33. app/build.gradle defaultConfig { applicationId 'net.rafaeltoledo.tests' minSdkVersion 16 targetSdkVersion 23 versionCode 1 versionName '0.0.1' testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' }
  34. 34. app/build.gradle androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2.2' androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test:rules:0.5'
  35. 35. app/build.gradle @RunWith(AndroidJUnit4.class) public class HomeActivityTest { @Rule public ActivityTestRule<HomeActivity> activityRule = new ActivityTestRule<>(HomeActivity.class); ... }
  36. 36. androidTest/. . . /HomeActivityTest.java public class HomeActivityTest { @Test public void checkIfRecyclerViewIsLoading() { // ... } }
  37. 37. androidTest/. . . /HomeActivityTest.java public class HomeActivityTest { @Test public void checkIfRecyclerViewIsLoading() { // êpa! Calma aí... } }
  38. 38. Testes e Dependências Externas como fazemos com a API? como fazemos com hardware? Como fazemos pra testar?
  39. 39. The FIRST Things for Unit Tests Fast! (Rápidos): tem que ser executados em alguns milissegundos ou segundos (Android) Isolated (Isolados): devem focar em uma porção pequena do código, alinhados com a definição de unitário Repeatable (Repetíveis): produzem os mesmos resultados todas as vezes que você o executa
  40. 40. The FIRST Things for Unit Tests Self-Validating (Auto-Validados): um teste só é um teste se ele se certifica de que as coisas estão certas. Testes não devem ter interação – devem poupar e não gastar seu tempo Timely (Oportuno): testes, se não se tornarem um hábito, podem facilmente ser “esquecidos”. E, no futuro, dificilmente esse débito venha a ser solucionado.
  41. 41. Mock
  42. 42. Abordagens de Mock Mock Objects: podemos programar o comportamento dos objetos para que respondam como desejamos (Mockito) Mock Requests: deixamos que os objetos se comportem normalmente e somente apontamos para uma outra API (MockWebServer)
  43. 43. Mock objects // Mockando a API com o mockito StackApi api = mock(StackApi.class); when(api.getUsers(anyInt()).thenReturn(createMockedResponse()); // Mockando callbacks ArgumentCaptor<Callback<ApiCollection<User>>> captor = forClass(Callback.class); verify(api.getUsersAsync(anyInt(), captor); captor.getValue().onSuccess(createMockedCall(), createMockedResponse());
  44. 44. Mock objects @RunWith(MockitoTestRunner.class) // Mockando a API com o mockito @Mock StackApi api; when(api.getUsers(anyInt()).thenReturn(createMockedResponse); // Mockando callbacks @Captor Callback<ApiCollection<User>>> captor; verify(api.getUsersAsync(anyInt(), captor); captor.getValue().onSuccess(createMockedCall(), createMockedResponse());
  45. 45. Mock Server // Mockando a API com o mockito MockWebServer server = new MockWebServer(); server.enqueue(new MockResponse() .setBody(json) // string! .addHeader("Header", "value") .setResponseCode(200));
  46. 46. Mas... Como fazer meu app utilizar esses objetos?
  47. 47. Mas... Como fazer meu app utilizar esses objetos? 1. DI / Setter
  48. 48. Mas... Como fazer meu app utilizar esses objetos? 1. DI / Setter 2. Reflection
  49. 49. DI / Setter // API Mockada que criamos :) apiSingleton.setApi(mockApiObject);
  50. 50. DI / Setter // API Mockada que criamos :) apiSingleton.setApi(mockApiObject); Porém, não é bom quando modificamos o nosso código de produção por causa do teste. Isso pode vir a gerar problemas na arquitetura ou brechas de segurança
  51. 51. DI / Setter public class ApiSingleton { // ... @VisibleForTesting public void setApi(MyApiInterface api) { this.api = api; } }
  52. 52. DI / Setter public class ApiSingleton { // ... @VisibleForTesting public void setApi(MyApiInterface api) { this.api = api; } } PS: Dagger é uma boa saída pra fazer essa troca
  53. 53. Reflection // Mudamos o valor do Singleton ApiModule module = ApiModule.getInstance(); Field field = module.getClass().getDeclaredField("api"); field.setAccessible(true); field.set(module, mockApi);
  54. 54. Reflection // Mudamos o valor do Singleton ApiModule module = ApiModule.getInstance(); Field field = module.getClass().getDeclaredField("api"); field.setAccessible(true); field.set(module, mockApi); // testCompile 'net.vidageek:mirror:1.6.1' new Mirror().on(module).set().field("api").withValue(mockApi);
  55. 55. Mas pode usar reflection no Android? Não é lento?
  56. 56. I – Testes unitários rodam na JVM. Não tem esse problema. II – É um teste de comportamento no emulador. Alguns segundos de setup são aceitáveis.
  57. 57. Code Coverage dados sobre quanto do código está sendo testado
  58. 58. Jacoco Plugin no Gradle Requer algumas configurações no arquivo de build
  59. 59. Notas Finais algumas dicas para os navegantes de primeira viagem
  60. 60. Test Butler Biblioteca + APK para garantir uma execução mais tranquila dos testes no emulador Permite controlar animações, rede, etc. https://github.com/linkedin/test-butler
  61. 61. Dicas Finais Testes Unitários != TDD Cuidado com os Mocks: - Não faça mock de tudo - Não faça mock de value objects (POJOs) - Não faça mock de tipos que você não tem - Mostre amor pelos seus testes <3
  62. 62. Dicas Finais Não use flavors para criação de mocks! - invasivo ao set-up do projeto - código duplicado - limita a configuração de comportamentos diferentes para a mesma unidade de código
  63. 63. Links google.github.io/android-testing-support-library github.com/googlesamples/android-testing blog.sqisland.com github.com/googlesamples/android-topeka github.com/chiuki/friendspell github.com/concretesolutions/requestmatcher github.com/rafaeltoledo/android-keep-testing
  64. 64. rafaeltoledo.net twitter.com/_rafaeltoledo blog.concretesolutions.com.br concretesolutions.com.br/carreira Rio de Janeiro – Rua São José, 90 – cj. 2121 Centro – (21) 2240-2030 São Paulo - Rua Sansão Alves dos Santos, 433 4º andar - Brooklin - (11) 4119-0449

×