Slide 1

Slide 1 text

Unit Testing Android Apps

Slide 2

Slide 2 text

@felipecsl Unit Testing Android Apps

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

8MM+ downloads 210k reviews 4.5 ★ average rating

Slide 5

Slide 5 text

Android app 2 developers

Slide 6

Slide 6 text

Android não foi desenhado com testabilidade em mente.

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

2. Técnicas 3. Ferramentas 1. Motivação

Slide 9

Slide 9 text

1. Motivação

Slide 10

Slide 10 text

Você ainda não está convencido do valor de escrever testes automatizados. Premissa

Slide 11

Slide 11 text

Tranquilidade: Consigo dormir à noite?

Slide 12

Slide 12 text

Maintainability: Consigo alterar o código facilmente?

Slide 13

Slide 13 text

O que causa Débito Técnico? The three sins of software development: http://blog.ionelmc.ro/2014/08/14/the-three-sins-of-software-development/

Slide 14

Slide 14 text

Medo “Melhor não mexer nesse código…"

Slide 15

Slide 15 text

Arrogância “Eu sei o que estou fazendo!”

Slide 16

Slide 16 text

Estimativas irreais “Isso é barbada.”

Slide 17

Slide 17 text

Não se trata de encontrar bugs

Slide 18

Slide 18 text

TDD é um processo de design

Slide 19

Slide 19 text

Código bem desenhado é facilmente testável

Slide 20

Slide 20 text

S.O.L.I.D.

Slide 21

Slide 21 text

http://www.agileapps.co.uk/methodology/continuous.html Red, Green, Refactor

Slide 22

Slide 22 text

#isTDDdead http://martinfowler.com/articles/is-tdd-dead/ http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html http://blog.8thlight.com/uncle-bob/2014/04/25/MonogamousTDD.html

Slide 23

Slide 23 text

2. Técnicas

Slide 24

Slide 24 text

http://martinfowler.com/bliki/TestPyramid.html

Slide 25

Slide 25 text

http://blog.stevensanderson.com/2009/08/24/writing-great-unit-tests-best-and-worst-practises/

Slide 26

Slide 26 text

3. Ferramentas

Slide 27

Slide 27 text

Testes Unitários

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

build.gradle http://gradleplease.appspot.com/ Gradle, please

Slide 30

Slide 30 text

build.gradle buildscript { repositories { mavenCentral() } dependencies { classpath 'org.robolectric:robolectric-gradle-plugin:0.12.0' } } apply plugin: 'robolectric'

Slide 31

Slide 31 text

build.gradle android { defaultConfig { // optional testInstrumentationRunner "com.example.MyAppTestRunner" } robolectric { include '**/*Test.class' } // optional sourceSets { androidTest { setRoot('src/test') } } }

Slide 32

Slide 32 text

build.gradle dependencies { compile 'com.android.support:appcompat-v7:20.0.0' // other dev dependencies... androidTestCompile 'junit:junit:4.10' androidTestCompile 'org.robolectric:robolectric:2.4-SNAPSHOT' androidTestCompile 'org.mockito:mockito-core:1.9.5' androidTestCompile 'org.hamcrest:hamcrest-library:1.3' }

Slide 33

Slide 33 text

JUnit + Hamcrest @Config(emulateSdk = 18) @RunWith(MyTestRunner.class) public class UserTest { private User user; @Before public void setUp() { user = new User(); user.setId(3); } @Test public void userShouldPersistFields() { assertFalse(user.isPublicAccount()); assertThat(user.getId(), equalTo(3)); } }

Slide 34

Slide 34 text

Robolectric Shadow Objects

Slide 35

Slide 35 text

Robolectric @RunWith(RobolectricTestRunner.class) @Test public void shouldHaveALogo() throws Exception { ImageView pivotalLogo = (ImageView) activity.findViewById(R.id.pivotal_logo); ShadowImageView shadowPivotalLogo = Robolectric.shadowOf(pivotalLogo); assertThat(shadowPivotalLogo.resourceId, equalTo(R.drawable.pivotallabs_logo)); }

Slide 36

Slide 36 text

Mockito @Before public void setUp() { HttpClient httpClient = mock(httpClient.class); ApiEndpoint endpoint = new ApiEndpoint(httpClient); } @Test public void userShouldPersistFields() { when(httpClient.get("/users/2")).thenReturn(new User()); endpoint.getUser(2); verify(httpClient).get("/users/2"); }

Slide 37

Slide 37 text

http://www.confreaks.com/videos/659-rubyconf2011-why-you-don-t-get-mock-objects Assert on messages, not state. Mocks

Slide 38

Slide 38 text

Rodando testes ./gradlew test

Slide 39

Slide 39 text

Rodando uma classe de teste apenas ./gradlew test --tests \ com.example.test.SomeClassTests

Slide 40

Slide 40 text

Bonus points: AssertJ Android assertThat(view).isGone(); assertThat(layout).isVisible() .isVertical() .hasChildCount(4) .hasShowDividers(SHOW_DIVIDERS_MIDDLE); https://github.com/square/assertj-android

Slide 41

Slide 41 text

Testes Funcionais

Slide 42

Slide 42 text

Ferramentas

Slide 43

Slide 43 text

Feature: Rating a stand Scenario: Find and rate a stand from the list Given I am on the foodstand list Then I should see a "rating" button Then I should not see "Dixie Burger & Gumbo Soup" When I touch the "rating" button Then I should see "Dixie Burger & Gumbo Soup" When I touch "Dixie Burger & Gumbo Soup" Then I should see details for "Dixie Burger & Gumbo Soup" When I touch the "rate_it" button Then I should see the rating panel When I touch "star5" And I touch "rate" Then "Dixie Burger & Gumbo Soup" should be rated 5 stars

Slide 44

Slide 44 text

Espresso Ferramentas

Slide 45

Slide 45 text

Integração Contínua

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

Test Cloud

Slide 49

Slide 49 text

Obrigado! @felipecsl http://felipecsl.com