Android testing
-
Upload
antonio-lopez-marin -
Category
Technology
-
view
23 -
download
0
Transcript of Android testing
ANDROID TESTING
ANTONIO LÓPEZ MARÍN
@tonilopezmr
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