Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testes no Android

Testes no Android

Apresentada no TDC Florianópolis 2016

Repositório: https://github.com/rafaeltoledo/android-keep-testing

Rafael Toledo

May 13, 2016
Tweet

More Decks by Rafael Toledo

Other Decks in Programming

Transcript

  1. 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
  2. Por que tenho 2 pastas de Testes? o que são

    as pastas test e androidTest no meu projeto?
  3. Testes instrumentados, que necessitam das classes do Android para a

    execução. São executados em emuladores ou devices reais androidTest
  4. Testes unitários executados na JVM (máquina local) Componentes externos geralmente

    são mockados (como as classes do Android)* Robolectric
  5. escopos de dependências // somente test testCompile 'junit:junit:4.12' testCompile 'org.robolectric:robolectric:3.1-rc1'

    // somente androidTest androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test:rules:0.5'
  6. 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); } }
  7. 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
  8. 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
  9. Biblioteca para a criação de mocks List mockedList = mock(List.class);

    mockedList.add("one"); mockedList.clear(); verify(mockedList).add("one"); verify(mockedList).clear();
  10. Framework para a criação de testes Instrumentados no Android Espresso

    AndroidJUnitRunner JUnit4 Rules UI Automator Android Testing Support Library
  11. Espresso Biblioteca para a escrita de testes 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
  12. 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
  13. “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
  14. @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
  15. 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
  16. 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
  17. 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));
  18. Design de classes Calculator c = new Calculator(); c.setFirstNumber(1); c.setSecondNumber(2);

    c.setOperation(Calculador.SUM); c.performOperation(); assertThat(c.getResult(), is(3));
  19. Design de classes Calculator c = new Calculator.Builder() .firstNumber(1) .secondNumber(2)

    .operation(Calculador.SUM) .build(); c.performOperation(); assertThat(c.getResult(), is(3));
  20. Nossa cobaia será um app que consome a API do

    StackOverflow e lista os usuários com a maior reputação no site
  21. app/build.gradle defaultConfig { applicationId 'net.rafaeltoledo.tests' minSdkVersion 16 targetSdkVersion 23 versionCode

    1 versionName '0.0.1' testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' }
  22. androidTest/. . . /HomeActivityTest.java public class HomeActivityTest { @Test public

    void checkIfRecyclerViewIsLoading() { // êpa! Calma aí... } }
  23. Testes e Dependências Externas como fazemos com a API? como

    fazemos com hardware? Como fazemos pra testar?
  24. 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
  25. 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.
  26. 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)
  27. 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());
  28. 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());
  29. Mock Server // Mockando a API com o mockito MockWebServer

    server = new MockWebServer(); server.enqueue(new MockResponse() .setBody(json) // string! .addHeader("Header", "value") .setResponseCode(200));
  30. 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
  31. DI / Setter public class ApiSingleton { // ... @VisibleForTesting

    public void setApi(MyApiInterface api) { this.api = api; } }
  32. DI / Setter public class ApiSingleton { // ... @VisibleForTesting

    public void setApi(MyApiInterface api) { this.api = api; } } PS: Dagger é uma boa saída pra fazer essa troca
  33. Reflection // Mudamos o valor do Singleton ApiModule module =

    ApiModule.getInstance(); Field field = module.getClass().getDeclaredField("api"); field.setAccessible(true); field.set(module, mockApi);
  34. 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);
  35. 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.
  36. 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
  37. rafaeltoledo.net twitter.com/_rafaeltoledo blog.concretesolutions.com.br 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