Android testing

Post on 11-Feb-2017

23 views 0 download

Transcript of Android testing

ANDROID TESTING

ANTONIO LÓPEZ MARÍN

@tonilopezmr

tonilopezmr@gmail.com

tonilopezmr.github.io

github.com/tonilopezmr

ANDROID TESTING

¿DE QUÉ

@tonilopezmr

VA ESTE CURSO ?

. TEST BASICS

. . UNIT TEST

. . . EL CAMINO A LA TESTABILIDAD

. . . . INTEGRATION TEST

. . . . . UI TEST

@tonilopezmr

UN TEST ES EL PROCESO DE EJECUTAR UN PROGRAMA CON EL OBJETIVO DE BUSCAR ERRORES

@tonilopezmr@tonilopezmr

¿POR QUÉ

@tonilopezmr

ESCRIBIR TEST ?

TIEMPO

@tonilopezmr

GANA

DINERO

@tonilopezmr

AHORRA

RESPONSABILIDAD

@tonilopezmr

ES TU

0

1

2

3

4

CAMINO HACIA ELÉXITO

@tonilopezmr

¿QUÉ

@tonilopezmr

ES UN TEST ?

DISEÑO

@tonilopezmr

UNA HERRAMIENTA DE

REFACTORIZAR

@tonilopezmr

LA ÚNICA MANERA DE

DOCUMENTACIÓN

@tonilopezmr

TU

AMIGO

@tonilopezmr

TU MEJOR

UN TEST ES QUIEN TE DICE QUE TU CÓDIGO FUNCIONA

@tonilopezmr@tonilopezmr@tonilopezmr

¿CÓMO ES

@tonilopezmr

UN TEST?

CLIENTE

@tonilopezmr

CERCANO AL

LENGUAJE NATURALPARECIDO AL

@tonilopezmr

TIPOS

@tonilopezmr

DE TEST

SUT

@tonilopezmr

FUNCIONES

CAJA NEGRA CAJA BLANCA

SYSTEM UNDER TEST

UI

Integration Test

Unit Test

@tonilopezmr

by Mike Cohn

@tonilopezmr

JVM UNIDAD INDEPENDIENTE

TEST DOUBLES REALLY FAST TEST

F.I.R.S.T

@tonilopezmr

JVM UNIDAD INDEPENDIENTE

TEST DOUBLES REALLY FAST TEST

F.I.R.S.T

@tonilopezmr

JVM UNIDAD INDEPENDIENTE

TEST DOUBLES REALLY FAST TEST

F.I.R.S.T

@tonilopezmr

JVM UNIDAD INDEPENDIENTE

TEST DOUBLES REALLY FAST TEST

F.I.R.S.T

@tonilopezmr

JVM UNIDAD INDEPENDIENTE

TEST DOUBLES REALLY FAST TEST

F.I.R.S.T

UNIT TEST

@tonilopezmr

TESTEA UNA UNIDAD

UNIT TEST

UNIT TEST

FAST ISOLATED REPEATABLE SELF-VALIDATION TIMELY

@tonilopezmr@tonilopezmr

PEQUEÑO

@tonilopezmr

SCOPE

UNIT TEST

@tonilopezmr

GIVEN WHEN THEN

ARRANGE ACT ASSERT

UNIT TEST

TEST DOUBLES

@tonilopezmrUNIT TEST

class Book { private int pages; private double price; public Book(int pages, double price) { this.pages = pages; this.price = price; } public int getPages() { return pages; }

public double getPrice() { return price; } }

@tonilopezmrTEST DOUBLE

TEST DOUBLE

DUMMY NO HACE NADA

@tonilopezmr

BookShop bookShop = new BookShop(); bookShop.add(new BookDummy()); bookShop.add(new BookDummy());

//debería devolver 2 bookShop.booksCount();

class BookDummy extends Book { @Override public int getPages() { return 0; } }

@tonilopezmr

TEST DOUBLE

DUMMY NO HACE NADA

@tonilopezmr

BookShop bookShop = new BookShop(); bookShop.add(new BookDummy()); bookShop.add(new BookDummy());

//debería devolver 2 bookShop.booksCount();

class BookDummy extends Book { @Override public int getPages() { return 0; } }

@tonilopezmr

TEST DOUBLE

DUMMY NO HACE NADA

@tonilopezmr

BookShop bookShop = new BookShop(); //Given bookShop.add(new BookDummy());bookShop.add(new BookDummy());

//debería devolver 2 bookShop.booksCount();

class BookDummy extends Book { @Override public int getPages() { return 0; } }

@tonilopezmr

TEST DOUBLE

DUMMY NO HACE NADA

@tonilopezmr

BookShop bookShop = new BookShop(); //Given bookShop.add(new BookDummy()); //WhenbookShop.add(new BookDummy());

//debería devolver 2 bookShop.booksCount();

class BookDummy extends Book { @Override public int getPages() { return 0; } }

@tonilopezmr

TEST DOUBLE

DUMMY NO HACE NADA

@tonilopezmr

BookShop bookShop = new BookShop(); //Given bookShop.add(new BookDummy()); //WhenbookShop.add(new BookDummy());

//debería devolver 2 //Then bookShop.booksCount();

class BookDummy extends Book { @Override public int getPages() { return 0; } }

@tonilopezmr

TEST DOUBLE

FAKES CERCANO A LO REAL

@tonilopezmr

class InMemoryBookRepository extends BookRepository { List<Book> books = new LinkedList<>(); @Override public List<Book> getAll() { return books; } }

inMemoryBookRepository = new InMemoryBookRepository();bookShop = new BookShop(inMemoryBookRepository); bookShop.store(new BookDummy());bookShop.store(new BookDummy()); inMemoryBookRepository.getAll(); //debería devolver 2

TEST DOUBLE

FAKES CERCANO A LO REAL

@tonilopezmr

class InMemoryBookRepository extends BookRepository { List<Book> books = new LinkedList<>(); @Override public List<Book> getAll() { return books; } }

inMemoryBookRepository = new InMemoryBookRepository(); bookShop = new BookShop(inMemoryBookRepository); bookShop.store(new BookDummy()); bookShop.store(new BookDummy()); inMemoryBookRepository.getAll(); //debería devolver 2

TEST DOUBLE

FAKES CERCANO A LO REAL

@tonilopezmr

class InMemoryBookRepository extends BookRepository { List<Book> books = new LinkedList<>(); @Override public List<Book> getAll() { return books; } }

inMemoryBookRepository = new InMemoryBookRepository(); bookShop = new BookShop(inMemoryBookRepository); bookShop.store(new BookDummy());bookShop.store(new BookDummy()); inMemoryBookRepository.getAll(); //debería devolver 2

TEST DOUBLE

FAKES CERCANO A LO REAL

@tonilopezmr

class InMemoryBookRepository extends BookRepository { List<Book> books = new LinkedList<>(); @Override public List<Book> getAll() { return books; } }

inMemoryBookRepository = new InMemoryBookRepository(); bookShop = new BookShop(inMemoryBookRepository); bookShop.store(new BookDummy()); bookShop.store(new BookDummy()); inMemoryBookRepository.getAll(); //debería devolver 2

TEST DOUBLE

STUBS RESPUESTA PREPARADA

@tonilopezmr

class BookStub extends Book {

@Override public double getPrice() { return 2.5; } }

BookShop bookShop= new BookShop();

bookShop.add(new BookStub());bookShop.add(new BookStub());bookShop.totalAmount(); //debería de volver 5

TEST DOUBLE

STUBS RESPUESTA PREPARADA

@tonilopezmr

class BookStub extends Book {

@Override public double getPrice() { return 2.5; } }

BookShop bookShop= new BookShop();

bookShop.add(new BookStub()); bookShop.add(new BookStub()); bookShop.totalAmount(); //debería de volver 5

TEST DOUBLE

STUBS RESPUESTA PREPARADA

@tonilopezmr

class BookStub extends Book {

@Override public double getPrice() { return 2.5; } }

BookShop bookShop= new BookShop();

bookShop.add(new BookStub()); bookShop.add(new BookStub()); bookShop.totalAmount(); //debería de volver 5

TEST DOUBLE

SPIES GUARDAN INFORMACIÓN

@tonilopezmr

class SpyBookApi extends BookRepository { public int getCallCount; public Response<Page> get(int page) { getCallCount++; return new ResponseDummy<Page>(); } }

SpyBookApi spyBookApi = new SpyBookApi();BookReader bookReader = new BookReader(spyBookApi);bookReader.load(new Book(100, 5d));bookReader.getAllPages();spyBookApi.getCallCount; //debería devolver 100

TEST DOUBLE

SPIES GUARDAN INFORMACIÓN

@tonilopezmr

class SpyBookApi extends BookRepository { public int getCallCount; public Response<Page> get(int page) { getCallCount++; return new ResponseDummy<Page>(); } }

SpyBookApi spyBookApi = new SpyBookApi(); BookReader bookReader = new BookReader(spyBookApi); bookReader.load(new Book(100, 5d)); bookReader.getAllPages(); spyBookApi.getCallCount; //debería devolver 100

TEST DOUBLE

SPIES GUARDAN INFORMACIÓN

@tonilopezmr

class SpyBookApi extends BookRepository { public int getCallCount; public Response<Page> get(int page) { getCallCount++; return new ResponseDummy<Page>(); } }

SpyBookApi spyBookApi = new SpyBookApi(); BookReader bookReader = new BookReader(spyBookApi);bookReader.load(new Book(100, 5d));bookReader.getAllPages();spyBookApi.getCallCount; //debería devolver 100

TEST DOUBLE

SPIES GUARDAN INFORMACIÓN

@tonilopezmr

class SpyBookApi extends BookRepository { public int getCallCount; public Response<Page> get(int page) { getCallCount++; return new ResponseDummy<Page>(); } }

SpyBookApi spyBookApi = new SpyBookApi(); BookReader bookReader = new BookReader(spyBookApi);bookReader.load(new Book(100, 5d)); bookReader.getAllPages(); spyBookApi.getCallCount; //debería devolver 100

TEST DOUBLE

MOCKS PREVISIVOS

@tonilopezmr

class BookApiMock extends BookRepository { public boolean createWasCalled; public void create(Book book) { createWasCalled = true; } }

SpyBookMock bookApiMock = new SpyBookMock();BookReader bookReader = new BookReader(bookApiMock); bookReader.load(new Book(100, 5d));bookReader.getAllPages();bookApiMock.callCount; //debería devolver 100 bookApiMock.createWasCalled; //debería devolver false

TEST DOUBLE

MOCKS PREVISIVOS

@tonilopezmr

class BookApiMock extends BookRepository { public boolean createWasCalled; public void create(Book book) { createWasCalled = true; } }

SpyBookMock bookApiMock = new SpyBookMock(); BookReader bookReader = new BookReader(bookApiMock); bookReader.load(new Book(100, 5d)); bookReader.getAllPages(); bookApiMock.callCount; //debería devolver 100 bookApiMock.createWasCalled; //debería devolver false

TEST DOUBLE

MOCKS PREVISIVOS

@tonilopezmr

class BookApiMock extends BookRepository { public boolean createWasCalled; public void create(Book book) { createWasCalled = true; } }

SpyBookMock bookApiMock = new SpyBookMock(); BookReader bookReader = new BookReader(bookApiMock); bookReader.load(new Book(100, 5d));bookReader.getAllPages();bookApiMock.callCount; //debería devolver 100 bookApiMock.createWasCalled; //debería devolver false

TEST DOUBLE

MOCKS PREVISIVOS

@tonilopezmr

class BookApiMock extends BookRepository { public boolean createWasCalled; public void create(Book book) { createWasCalled = true; } }

SpyBookMock bookApiMock = new SpyBookMock(); BookReader bookReader = new BookReader(bookApiMock); bookReader.load(new Book(100, 5d));bookReader.getAllPages(); bookApiMock.callCount; //debería devolver 100 bookApiMock.createWasCalled; //debería devolver false

TEST DOUBLE

DUMMY NO HACE NADA FAKES CERCANO A LO REAL STUBS RESPUESTA PREPARADA SPIES GUARDAN INFORMACIÓN MOCKS PREVISIVOS

@tonilopezmr@tonilopezmr

HERRAMIENTAS

@tonilopezmr

UNIT TEST

@tonilopezmrUNIT TEST

JUNIT 4 HAMCREST MOCKITO

@tonilopezmr@tonilopezmrUNIT TEST

assertEquals() assertTrue() assertNull() assertSame()assertArrayEquals() assertThat()

@tonilopezmr@tonilopezmr

JUNIT 4assertFalse() assertNotNull() assertNotSame()

assertEquals("patata", patataString)

http://junit.org/junit4/

assertEquals() assertTrue() assertNull() assertSame()assertArrayEquals() assertThat()

@tonilopezmr@tonilopezmr

JUNIT 4assertFalse() assertNotNull() assertNotSame()

assertEquals("patata", patataString)

http://junit.org/junit4/

@tonilopezmr@tonilopezmr

HAMCRESTassertThat(patataString, is("patata"))

http://hamcrest.org/

@tonilopezmr@tonilopezmr

HAMCRESTassertThat(patataString, is("patata"))

http://hamcrest.org/

@tonilopezmr@tonilopezmr

HAMCRESTis()nullValue()sameInstance()any() contains()

not()notNullValue() sameInstance()

assertThat(patataString, is(not(“patata”)))

assertThat(patataList, contains(“patata”,“boniato”)))

assertThat(patataList, not(contains(“patata”))))

http://hamcrest.org/

@tonilopezmr@tonilopezmr

HAMCRESTis()nullValue()sameInstance()any() contains()

not()notNullValue() sameInstance()

assertThat(patataString, is(not(“patata”)))

assertThat(patataList, contains(“patata”,“boniato”)))

assertThat(patataList, not(contains(“patata”))))

http://hamcrest.org/

@tonilopezmr@tonilopezmr

HAMCRESTis()nullValue()sameInstance()any() contains()

not()notNullValue() sameInstance()

assertThat(patataString, is(not(“patata”)))

assertThat(patataList, contains(“patata”,“boniato”)))

assertThat(patataList, not(contains(“patata”))))

http://hamcrest.org/

@tonilopezmr@tonilopezmr

HAMCRESTis()nullValue()sameInstance()any() contains()

not()notNullValue() sameInstance()

assertThat(patataString, is(not(“patata”)))

assertThat(patataList, contains(“patata”,“boniato”)))

assertThat(patataList, not(contains(“patata”))))

http://hamcrest.org/

@tonilopezmr@tonilopezmr

MOCKITOBook book = mock(Book.class)

when(book.getPrice()).thenReturn(4.5)

verify(bookApi).getPages();

given(book.getPrice()).willReturn(4.5)

http://mockito.org/

@tonilopezmr@tonilopezmr

MOCKITOBook book = mock(Book.class)

when(book.getPrice()).thenReturn(4.5)

verify(bookApi).getPages();

given(book.getPrice()).willReturn(4.5)

http://mockito.org/

@tonilopezmr@tonilopezmr

MOCKITOBook book = mock(Book.class)

when(book.getPrice()).thenReturn(4.5)

verify(bookApi).getPages();

given(book.getPrice()).willReturn(4.5)

http://mockito.org/

@tonilopezmr@tonilopezmr

MOCKITOBook book = mock(Book.class)

when(book.getPrice()).thenReturn(4.5)

verify(bookApi).getPages();

given(book.getPrice()).willReturn(4.5)

http://mockito.org/

VALE, VALE, SI YO QUIERO HACER TESTS, PERO…

¿CÓMO LO HAGO?

¯\_( )_/¯

@tonilopezmr

GO TO PRACTICE

@tonilopezmr

ANDROID TESTING

VALE, VALE, SI YO SE HACER TESTS, PERO…

¿QUÉ PASA SI MI CÓDIGO NO ES TESTEABLE?

¯\_( )_/¯

@tonilopezmr

HAZLOTESTEABLE

@tonilopezmr

LA ARQUITECTURA DEL SOFTWARE TIENE QUE OCULTAR LOS DETALLES DE IMPLEMENTACIÓN

@tonilopezmr@tonilopezmr@tonilopezmr

SINGLE RESPONSIBILITY OPEN/CLOSE LISKOV SUBSTITUTION INTERFACE SEGREGATION DEPENDENCY INVERSION

@tonilopezmr@tonilopezmr

SOLID @tonilopezmr

SINGLE RESPONSIBILITY

UN OBJETO HACE UNA ÚNICA COSA

UNA CLASE MANEJA VARIAS CAPAS NÚMERO DE MÉTODOS PUBLICOS NOS CUESTA TESTEAR LA CLASE

SOLID @tonilopezmr

SINGLE RESPONSIBILITY

UNA CLASE MANEJA VARIAS CAPAS NÚMERO DE MÉTODOS PUBLICOS NOS CUESTA TESTEAR LA CLASE

UN OBJETO HACE UNA ÚNICA COSA

SOLID @tonilopezmr

SINGLE RESPONSIBILITY

UNA CLASE MANEJA VARIAS CAPAS NÚMERO DE MÉTODOS PUBLICOS NOS CUESTA TESTEAR LA CLASE

UN OBJETO HACE UNA ÚNICA COSA

SOLID @tonilopezmr

SINGLE RESPONSIBILITY

UNA CLASE MANEJA VARIAS CAPAS NÚMERO DE MÉTODOS PUBLICOS NOS CUESTA TESTEAR LA CLASE

UN OBJETO HACE UNA ÚNICA COSA

SOLID @tonilopezmr

OPEN/CLOSE

ABIERTA A EXTENSIÓN CERRADA A MODIFICACIÓN

ESCRIBIR NUEVAS FUNCIONALIDADES NO DEBE AFECTAR A NUESTRO CÓDIGO YA ESCRITO

SOLID @tonilopezmr

LISKOV SUBSTITUTION

EXTENDER UNA CLASE SIN ALTERAR SU COMPORTAMIENTO

TODO MÉTODO SOBRESCRITO DEBE TENER IMPLEMENTACIÓN NO VALE DEJAR MÉTODOS VACÍOS

NOS AYUDA A USAR HERENCIA CORRECTAMENTE

SOLID @tonilopezmr

LISKOV SUBSTITUTION

EXTENDER UNA CLASE SIN ALTERAR SU COMPORTAMIENTO

TODO MÉTODO SOBRESCRITO DEBE TENER IMPLEMENTACIÓN NO VALE DEJAR MÉTODOS VACÍOS

NOS AYUDA A USAR HERENCIA CORRECTAMENTE

SOLID @tonilopezmr

LISKOV SUBSTITUTION

EXTENDER UNA CLASE SIN ALTERAR SU COMPORTAMIENTO

TODO MÉTODO SOBRESCRITO DEBE TENER IMPLEMENTACIÓN NO VALE DEJAR MÉTODOS VACÍOS

NOS AYUDA A USAR HERENCIA CORRECTAMENTE

SOLID @tonilopezmr

LISKOV SUBSTITUTION

TODO MÉTODO SOBRESCRITO DEBE TENER IMPLEMENTACIÓN NO VALE DEJAR MÉTODOS VACÍOS

NOS AYUDA A USAR HERENCIA CORRECTAMENTE

EXTENDER UNA CLASE SIN ALTERAR SU COMPORTAMIENTO

SOLID @tonilopezmr

INTERFACE SEGREGATION

NINGUNA CLASE DEPENDE DE MÉTODOS QUE NO USA

INTERFACES MÁS PEQUEÑAS “SEGREGACIÓN”

SOLID @tonilopezmr

DEPENDENCY INVERSION

OCULTAR DETALLES DE IMPLEMENTACIÓN

LÓGICA DE NEGOCIO QUE DEPENDE DE DETALLES DE IMPLEMENTACIÓN ¿CUALES SON LAS DEPENDENCIAS?

MUY DIFÍCIL HACER TEST

Depender de abstracciones nunca de concreciones

SOLID @tonilopezmr

DEPENDENCY INVERSION

OCULTAR DETALLES DE IMPLEMENTACIÓN

LÓGICA DE NEGOCIO QUE DEPENDE DE DETALLES DE IMPLEMENTACIÓN ¿CUALES SON LAS DEPENDENCIAS?

MUY DIFÍCIL HACER TEST

Depender de abstracciones nunca de concreciones

SOLID @tonilopezmr

DEPENDENCY INVERSION

OCULTAR DETALLES DE IMPLEMENTACIÓN

LÓGICA DE NEGOCIO QUE DEPENDE DE DETALLES DE IMPLEMENTACIÓN ¿CUALES SON LAS DEPENDENCIAS?

MUY DIFÍCIL HACER TEST

Depender de abstracciones nunca de concreciones

SOLID @tonilopezmr

DEPENDENCY INVERSION

LÓGICA DE NEGOCIO QUE DEPENDE DE DETALLES DE IMPLEMENTACIÓN ¿CUALES SON LAS DEPENDENCIAS?

MUY DIFÍCIL HACER TEST

OCULTAR DETALLES DE IMPLEMENTACIÓNDepender de abstracciones nunca de concreciones

DEPENDENCY INVERSION

@tonilopezmr

NOS PERMITE REMPLAZAR NUESTRO CÓDIGO DE PRODUCCIÓN POR NUESTRO TEST DOUBLE QUE NECESITEMOS

@tonilopezmr@tonilopezmr@tonilopezmr

SCOPE

@tonilopezmr

ELEGIR EL

INTERFACES

@tonilopezmr

USO DE

INTERFACES

@tonilopezmr

USO DE

NO SIEMPRE

MUY BAJO

@tonilopezmr

NIVEL DE ACOPLAMIENTO

CONSTRUCTOR

@tonilopezmr

DEPENDENCIAS POR

SQLiteManager sqliteManager = new SQLiteManager(); CharacterCache characterCache = new CharacterCache(sqliteManager);

CharacterValidator characterValidator = new CharacterValidator(); CharacterApi characterApi = new CharacterApi(); CharacterRepository characterRepository =

new CharacterRepository(characterValidator, characterApi, characterCache); CharacterListPresenter characterListPresenter = new CharacterListPresenter(characterRepository);

@tonilopezmr

SQLiteManager sqliteManager = new SQLiteManager(); CharacterCache characterCache = new CharacterCache(sqliteManager);

CharacterValidator characterValidator = new CharacterValidator(); CharacterApi characterApi = new CharacterApi(); CharacterRepository characterRepository =

new CharacterRepository(characterValidator, characterApi, characterCache); CharacterListPresenter characterListPresenter = new CharacterListPresenter(characterRepository);

@tonilopezmr

SQLiteManager sqliteManager = new SQLiteManager(); CharacterCache characterCache = new CharacterCache(sqliteManager);

CharacterValidator characterValidator = new CharacterValidator(); CharacterApi characterApi = new CharacterApi(); CharacterRepository characterRepository =

new CharacterRepository(characterValidator, characterApi, characterCache); CharacterListPresenter characterListPresenter = new CharacterListPresenter(characterRepository);

@tonilopezmr

SQLiteManager sqliteManager = new SQLiteManager(); CharacterCache characterCache = new CharacterCache(sqliteManager);

CharacterValidator characterValidator = new CharacterValidator(); CharacterApi characterApi = new CharacterApi(); CharacterRepository characterRepository =

new CharacterRepository(characterValidator, characterApi, characterCache); CharacterListPresenter characterListPresenter = new CharacterListPresenter(characterRepository);

@tonilopezmr

FACTORIAS

@tonilopezmr

SE PUEDE RESOLVER MEDIANTE

DEPENDENCY INJECTION

@tonilopezmr

DEPENDENCIAS

@tonilopezmr

CONFIGURACIÓN DE

ABSTRACCIONES

@tonilopezmr

EXTRAER DONDE SE DEPENDE DE

MODEL VIEW PRESENTER

@tonilopezmr

ARCHITECTURE PATTERN

@tonilopezmr

VIEW

PRESENTER

MODEL

presenter.cargaPersonajes

modelo.damePersonajestoma personajes

vista.dejaDeMostrarUnLoader

vista.mostrarXBotones

vista.mostrarPersonajes

@tonilopezmrVIEW

public interface CharacterListView {

void initUI(); void show(List<GoTCharacter> characterList); void showEmptyCase(); void hideEmptyCase(); void showProgressBar(); void hideProgressBar(); void showCharacterListError(); void showNetworkError(); }

@tonilopezmrPRESENTER

public class CharacterListPresenter { private Domain domain; public CharacterListPresenter(Domain domain) { this.domain = domain; } public void init() { view.initUi(); view.hideProgressBar(); view.show(domain.getAll()); } public void setView(CharacterListView view) { this.view = view; }

}

@tonilopezmrMODEL

BUSINESS LOGIC

EJEMPLO

@tonilopezmr

GAME OF THRONES

@tonilopezmr

LISTAR PERSONAJES LISTAR ORDENADOS POR NOMBRE PERSONAJES POR CASA AÑADIR PERSONAJES

VALE, VALE, SI EL MVP LO ENTIENDO, PERO…

¿CÓMO AÑADO COSAS A EL INJECTOR?

¯\_( )_/¯

@tonilopezmr

GO TO PRACTICE

@tonilopezmr

@tonilopezmr

INTEGRACIÓN DE MÓDULOS MI INTEGRACIÓN CON MI API FUNCIONA

NO TAN RÁPIDOS

@tonilopezmr

INTEGRACIÓN DE MÓDULOS MI INTEGRACIÓN CON MI API FUNCIONA

NO TAN RÁPIDOS

@tonilopezmr

INTEGRACIÓN DE MÓDULOS MI INTEGRACIÓN CON MI API FUNCIONA

NO TAN RÁPIDOS

@tonilopezmr

INTEGRACIÓN DE MÓDULOS MI INTEGRACIÓN CON MI API FUNCIONA

NO TAN RÁPIDOS

MÁS GRANDE

@tonilopezmr

SCOPE

API CLIENT

@tonilopezmr

REQUEST/RESPONSE

@tonilopezmr

HTTP

JSON

@tonilopezmr

PARSING

HEADER

@tonilopezmr

ASSERTING

API

@tonilopezmr

FAKE

SERVIDOR

@tonilopezmr

RUNTIME TEST

MOCKWEBSERVER

@tonilopezmr

https://github.com/square/okhttp/tree/master/mockwebserver

public class MockWebServerTest { private MockWebServer server; @Before public void setUp() throws Exception { this.server = new MockWebServer(); this.server.start(); } @After public void tearDown() throws Exception { this.server.shutdown(); } protected String getBaseEndpoint() { return server.url("/").toString(); } }

https://github.com/square/okhttp/tree/master/mockwebserver

public class IntegrationApiTest extends MockWebServerTest {

protected void enqueueMockResponse(String body) { MockResponse mockResponse = new MockResponse(); mockResponse.setResponseCode(200); mockResponse.setBody(body); server.enqueue(mockResponse); }

}

https://github.com/square/okhttp/tree/master/mockwebserver

GO TO PRACTICE

@tonilopezmr

@tonilopezmr

FRAMEWORKS FRAGILES

END - TO -END LENTA

@tonilopezmr

FRAMEWORKS FRAGILES

END - TO -END LENTA

@tonilopezmr

FRAMEWORKS FRAGILES

END - TO -END LENTA

@tonilopezmr

FRAMEWORKS FRAGILES

END - TO -END LENTA

@tonilopezmr

FRAMEWORKS FRAGILES

END - TO -END LENTA

AUTOMATIC UI TESTING

@tonilopezmr@tonilopezmr@tonilopezmr

ESPRESSO

@tonilopezmr

onView(ViewMatcher) .perform(ViewAction) .check(ViewAssertion)

@tonilopezmr

onView(ViewMatcher) .perform(ViewAction) .check(ViewAssertion)

ViewMatcher

implement Matcher<? super View>

@tonilopezmr

onView(ViewMatcher) .perform(ViewAction) .check(ViewAssertion)

ViewAction

click()

@tonilopezmr

onView(ViewMatcher) .perform(ViewAction) .check(ViewAssertion)

ViewAssertion

assert views

@tonilopezmr

onView(withId(R.id.button)) .perform(click()) .check(isDisplayed())

@tonilopezmr

onView(ViewMatcher) .perform(ViewAction) .check(ViewAssertion)

onData(ObjectMatcher) .DataOptions .perform(ViewAction) .check(ViewAssertion)

@tonilopezmr

onData(ObjectMatcher) .DataOptions .perform(ViewAction) .check(ViewAssertion)

ObjectMatcher

implement Matcher<? super Object>

@tonilopezmr

onData(ObjectMatcher) .DataOptions .perform(ViewAction) .check(ViewAssertion)

DataOptions

AdapterView, GridView

@tonilopezmr

@tonilopezmr

@tonilopezmr

@tonilopezmr

GO TO PRACTICE

@tonilopezmr