Testes de Ponta a Ponta
Eduardo Carrara - @DuCarrara
Android Developer
Elias Nogueira - @eliasnogueira
Agile Coach @ Sicredi
Introdução
Unit Test
IntegrationTest
UITest
Pirâmide de Automação de Teste
Pipeline ideal para execução dos testes
Análise Estática
Testes Unitários
Testes de Integração
Testes de Serviços
Testes de Aceitação
Testes Funcionais
Mock
Execução Paralela
Smoke Test
Testes Unitários
Photo by Chad Kirchoff on Unsplash
Unidades de TrabalhoIsoláveis de dependências Externas
Possibilitam testes rápidos
Pequenas como métodos ou grandes como conjuntos de classes
Lembrete: Arrange, Act, Assert
Tipos de Testes Unitários (by The Art of Unit Testing)
Value Based Testing
Interaction Based Testing
State Based Testing
MockingDeve ajudar a lidar com as dependências de maneira simples
Prover objetos dublês (mocks, stubs etc)
Isolar a unidade a ser testada
Fornecer controle sobre comportamento e estado
Code Time!
Value Based Unit Test
@Test fun searchForBookBy_whenCalled_withValidISBN_returnsBookSuccessfully() {
// Arrange
val fakeISBN = "8575224123"
val (bookCollectionToBeReturned, expectedBook)
= getInputAndExpectedDataFrom(inputResource)
val googleBooksRestApi: GoogleBooksRestApi = mock {
on { searchVolumeData(any(), any()) }
.doReturn( Single.just(bookCollectionToBeReturned))
}
// Act and Assert
GoogleBooksRestDataSource(googleBooksRestApi)
.searchForBookBy(fakeISBN)
.test().assertValue(expectedBook).assertComplete()
}
State Based Unit Test
@Test fun getByIsbn_whenCalled_withoutIsbnInCache_cachesBook() {
// Arrange
val fakeBook = getFakeBook()
whenever(bookRemoteDataSource.searchForBookBy(fakeBook.isbn10))
.thenReturn(Maybe.just(fakeBook))
// Act
bookCachedRepository.getByIsbn(fakeBook.isbn10).test().assertComplete()
// Assert
bookContentProviderCache[fakeBook.isbn10].test().assertComplete()
.assertValue{ returnedBook ->
assertSame(expected = fakeBook, real = returnedBook) }
}
Interaction Based Unit Test
@Test fun getByIsbn_whenCalled_withExistingIsbnInCache_neverCallsRemoteDataSource() {
// Arrange
val cachedFakeBook = insertFakeBookIntoCache()
var remoteDataSourceWasTriggered = false
onBookRemoteDataSourceSearchForBookByCompletedTriggers {
remoteDataSourceWasTriggered = true }
// Act
bookCachedRepository.getByIsbn(cachedFakeBook.isbn10)
.test().assertComplete()
// Assert No Interaction
assertThat(remoteDataSourceWasTriggered, `is`(false))
}
Robolectric + Mockito Tip of the Day@RunWith(RobolectricTestRunner::class)
@Config(constants = BuildConfig::class)
class BookCachedRepositoryTest {
@get:Rule
val mockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS)
@get:Rule
val robolectricVilibraProviderRule = RobolectricVilibraProviderRule()
@Mock
lateinit var bookRemoteDataSource: BookRemoteDataSource
private val bookContentProviderCache =
BookContentProviderCache(RuntimeEnvironment.application)
private lateinit var bookCachedRepository: BookCachedRepository
}
Testes Integrados
Photo by Brady Holt on Wikimedia
Mock Driver
Android Instrumentation TestsQuando não conseguimos nos livrar das dependências
Não são tão rápidos nem tão simples como testes unitários
Geralmente focados em testes funcionais baseados na UI
Como seu usuário interage com o app?
Android Testing Support LibraryAndroidJUnitRunner + JUnit4 Rules + Espresso + UIAutomator
Muito focado em testes de Interface do Usuário
Instrumentation Testing RobotsUm Pattern com foco na organização dos testes
Melhorar a legibilidade e manutenção dos testes
Separar "o como testar" do "o que testar"
Muito similar aos Page Objects
Test(O que)
Robot(O como)
View
Presenter(O como)
Fake Model(O que)
Code Time!
Simple Espresso Test @Test fun whenOpened_withOneBookLending_displayBookLendingCorrectly_pureEspresso() {
val fakeBook = testDataRule.fakeBook
Espresso.onView(
Matchers.allOf<View>(
ViewMatchers.withId(R.id.book_name_text_view),
ViewMatchers.hasSibling(ViewMatchers.withText(fakeBook.title))
))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
Espresso.onView(
Matchers.allOf<View>(
ViewMatchers.withId(R.id.book_author_text_view),
ViewMatchers.hasSibling(ViewMatchers
.withText(fakeBook.authors.joinToString(",")))))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
}
Instrumentation Testing Robot (ITR)
@Test
fun whenOpened_withOneBookLending_displayBookLendingCorrectly() {
val fakeBook = testDataRule.fakeBook
lentBooks {
checkForBookTitle(fakeBook.title)
checkForBookAuthors(fakeBook.authors.joinToString(","))
}
}
ITR - Internals
fun lentBooks(func: LentBooksRobot.() -> Unit) = LentBooksRobot().apply { func() }
class LentBooksRobot {
fun checkForBookTitle(expectedTitle: String): LentBooksRobot {
Espresso.onView(
Matchers.allOf<View>(
ViewMatchers.withId(R.id.book_name_text_view),
ViewMatchers.hasSibling(ViewMatchers.withText(expectedTitle))
))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
return this
}
}
ITR - Outro Exemplo
@Test
fun lendBookToContact() {
val expectedIsbn = "8575224123"
val expectedBookTitle
= "Dominando o Android"
lentBooks {
addBookLending()
}
searchBook {
fillIsbn(expectedIsbn)
confirm()
}
bookDetails {
checkForBookTitle(expectedBookTitle)
checkForBookIsbn10("ISBN-10: $expectedIsbn")
lend()
}
contacts {
pickContact("Meu Irmao")
}
lentBooks {
checkForBookTitle(expectedBookTitle)
}
...
Testes de Aceitação
Photo by TireRack.com
Page ObjectsUm Pattern com foco na organização dos testes
Melhorar a legibilidade e manutenção dos testes
Separar "o como testar" do "o que testar"
public void fillISBN(String isbnText) {
isbn.sendKeys(isbnText);
driver.hideKeyboard();
}
public void clickInConfirm() {
confirm.click();
}
Transformar ações do usuário em código
Page Objects
Scan Livro Preencher ISBN Emprestar Livro Selecionar contato Ver Detalhes Livro
Teste de Aceitação (E2E) - Emprestar um livro a um contato
@Test
public void leandABook() {
MainPage mainPage = new MainPage(driver);
mainPage.clickAddLeaging();
BookScanPage scan = new BookScanPage(driver);
scan.fillISBN("8575224638");
BookDetailsPage details = new BookDetailsPage(driver);
assertEquals("Dominando o Android 2ª edição", details.getBookTitle());
details.clickLeandThisBook();
ContactPage contactPage = new ContactPage(driver);
contactPage.clickMenuSearchIcon();
mainPage = new MainPage(driver);
assertEquals("Dominando o Android 2ª edição", mainPage.getBookName());
}
Photo by Rian MacGuire on PixelBay
Testes Além do app
Testar os serviços (REST | WebService)Testar se endpoint está ativo
Teste Funcional
Teste de Contrato
Teste de Aceitação (fluxo da API sem UI)
Pensamentos FinaisTeste as engrenagens de forma isoladaTestes as engrenagens em conjunto
Foco nas interações dos usuários na aplicação
Não esqueça de testar os seus serviços
Perguntas?
Eduardo Carrara
@DuCarrara
Obrigado!
github.com/ecarrara-araujo
Elias Nogueira
@eliasnogueira
github.com/eliasnogueira
Referências1. Testing on Android Documentation by Android Developers2. Android Testing Patterns Youtube Playlist3. The Art of Unit Testing by Roy Osherove4. Instrumentation Testing Robots by Jake Warthon5. Page Objects by Martin Fowler6. Test Pyramid7. Page Objects8. Android Tests by Goggle Samples9. Android Testing Templates by Google Samples
10. Espresso Cheat Sheet
Códigohttps://github.com/ecarrara-araujo/vilibrahttps://github.com/eliasnogueira/vilibra-testing
Top Related