Material:
Melhorando seu App com Kotlin e Testes
Eduardo Carrara
@DuCarrara
Android Developer
Material:
Adoramos melhorar nossas aplicações!
Para nossos usuários e nós mesmos!
Material: Photo by Carl Rice on carlrice.io
Kotlin esta aí!
Material:
Null Safety
Menor verbosidade
Integração com Java
Properties
String Templates
Sem Checked Exceptions
Expressões Lambda
Extension Functions
Inline Functions
Data Classes
Material:
Functions
fun noArgumentsFunction() { /* ... */ }
fun withArgumentsFunction(firstArgument: String, secondArgument: Int){
/* ... */
}
fun oneLiner() = "No value"
fun sum(a: Int, b: Int) = a + b
Material:
Variables
// Immutable
val variable: Int = 5
val variable2: String
val variable3 = 345
// Mutable
var variable4 = "Testing"
var variable5 = listOf("One",
"Two", "Three")
var variable6: Long
Material:
Classes
open class SimpleClass
class ComplexClass : SimpleClass()
data class DataClass(val immutableValue: Int = 123)
object ObjectClass
fun justForFun() {
val dataClassInstance = DataClass()
val dataClassInstance2 = DataClass(immutableValue = 438)
print(dataClassInstance.immutableValue)
}
Material:
Lambdas
// lambda ou função anônima
val lambdaFunction = { a: Int, b: Int -> a + b }
val toIntLambda = { value: String -> value.toInt() }
// "Useless" Higher Order Function
fun map(value: String, transform: (String) -> Int) = transform(value)
fun messingAround() {
print(map("458", toIntLambda))
print(map("458", { s -> s.toInt() }))
}
Material:
Extension Functions
fun String.toInt(): Int = java.lang.Integer.parseInt(this)
fun Int.isNegative(): Boolean = this < 0
Material:
Material:
Como começar a refatorar meu app?
Qual o estado atual do meu código?
Material:
Minha App
Um olhar sobre a Arquitetura
Feature A
Presentation
Domain
Data
Feature B
Presentation
Domain
Data
Feature C
Presentation
Domain
Data
Material:
Megazord Monolith
Um Olhar sobre Arquitetura (Realidade)
Component
Zord
Component
Zord
Component
Zord
Component
Zord
Component
Zord
Component
Zord
Component
Zord
Component
Zord
Material:
Vá em frente e quebre umas features por aí...
ou
Tentar algo mais tranquilo?
Photo by The Matrix Movie
Material:
Que tal começar
com testes?
Photo by Danielle MacInnes on Unsplash
Material:
Por onde começar?
Testes funcionais com foco no usuário
Escolha uma delas para começar
Entenda e mapeie as funcionalidades mais importantes
Utilize Espresso + Kotlin para automatizar os testes
Material:
Crash Course
Espresso Cheat Sheet
Material:
ViewMatcher ViewAction ViewAssertion
Crash Course
withId
withText
isDisplayed
isVisible
is
...
click
doubleClick
longClick
pressBack
scrollTo
...
matches
doesNotExist
isLeftOf
isAbove
...
Material:
Anatomia de um Instrumentation Test
@RunWith(AndroidJUnit4::class)
class TestClass {
@get:Rule
var activityInitializationRule =
ActivityTestRule<TestActivity>(TestActivity::class.java)
@Test
fun simpleTest() { /* test stuff */ }
}
Test Runner
Class Definition
Initialization Rule
Test
Material:
Um teste não tão simples!
@Test
fun whenOpened_withOneBookLending_displayBookLendingCorrectly_pureEspresso() {
val fakeBook = testDataRule.fakeBook
onView(allOf<View>(withId(R.id.book_name_text_view),
hasSibling(withText(fakeBook.title)))
).check(matches(isDisplayed()))
onView(allOf<View>(withId(R.id.book_author_text_view),
hasSibling(withText(fakeBook.authors.joinToString(","))))
).check(matches(isDisplayed()))
}
Code: https://goo.gl/RR7DxW
Material:
Realmente novo?
Material:
Instrumentation Testing Robots
Um 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)
Material:
Um Teste mais Feliz
@Test
fun whenOpened_withOneBookLending_displayBookLendingCorrectly() {
val fakeBook = testDataRule.fakeBook
lentBooks {
checkForBookTitle(fakeBook.title)
checkForBookAuthors(fakeBook.authors.joinToString(","))
}
}
Code: https://goo.gl/RR7DxW
Material:
ITR Internals
class LentBooksRobot {
fun checkForBookTitle(expectedTitle: String): LentBooksRobot {
onView(allOf<View>(withId(R.id.book_name_text_view),
hasSibling(withText(expectedTitle)))
).check(ViewAssertions.matches(isDisplayed()))
return this
}
}
Code: https://goo.gl/c4K6bo
Material:
ITR Internals
class LentBooksRobot {
...
}
fun lentBooks(func: LentBooksRobot.() -> Unit) =
LentBooksRobot().apply { func() }
Code: https://goo.gl/c4K6bo
Material:
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)
}
...
Code: https://goo.gl/cbMLLA
Material:
Suficiente?
Temos nossa "proteção" inicial contra bugs, mas lembre-se ...
Maior probabilidade de Test Flakiness
Testes instrumentados são mais lentos
E agora?
Material:
Hora de atacar o Megazord!
Material:
Parta para o Refactoring
Modularize, Isole Componentes, Crie abstrações
Escreva testes unitários!
Adote padrões de Arquitetura
Material:
Testes Unitários
Verificam os "internals" da aplicação
Rápidos e Abrangentes
Viáveis com baixo acoplamento e em pequenas unidades
Utilize JUnit + Mockito (ou outras ferramentas de mocking)
Material:
Exemplo - Vilibra
App Data Layer
BookRepository
Outras
Camadas
RemoteDataSource
LocalDataSource
database
Serviços Externos
Material:
Testando o BookRepository
interface BookRepository {
fun getByIsbn(isbn: String): Maybe<Book>
}
class BookCachedRepository(
private val bookRemoteDataSource: BookRemoteDataSource,
private val bookLocalCache: BookLocalCache
) : BookRepository {
override fun getByIsbn(usbn: String): Maybe<Book> {
/* ... */
}
}
Material:
Testando o BookRepository
@RunWith(JUnit4::class)
class BookCachedRepositoryTest {
@Test
fun testingOurRepository() { }
}
Test Runner
Test
Material:
Testando o BookRepository - Mocks
@RunWith(MockitoJUnitRunner::class)
class BookCachedRepositoryTest {
}
@Mock
lateinit var bookRemoteDataSource: BookRemoteDataSource
@Mock
lateinit var bookLocalDataSource: BookLocalCache
Note: Mock the unmockable: opt-in mocking of final classes/methods
Material:
@RunWith(MockitoJUnitRunner::class)
class BookCachedRepositoryTest {
/* Mocks Configuration */
}
Testando o BookRepository - Tests
@Test
fun getByIsbn_whenCalled_withExistingIsbnInCache_returnsCachedBook() {
//Arrange
//Act
//Assert
}
Code: https://goo.gl/Ybh62x
Material:
Testando o BookRepository - Tests
@Test
fun getByIsbn_whenCalled_withExistingIsbnInCache_returnsCachedBook() {
//Arrange
//Act & Assert
}
val fakeBook = prepareFakeBook()
whenever(bookLocalDataSource[fakeBook.isbn10])
.thenReturn(Maybe.just(fakeBook))
val bookCachedRepository =
BookCachedRepository(bookRemoteDataSource, bookLocalDataSource)
bookCachedRepository.getByIsbn(fakeBook.isbn10)
.test()
.assertValue(fakeBook)
Code: https://goo.gl/Ybh62x
Material:
Último Truque!
@Test
fun getByIsbn_whenCalled_withExistingIsbnInCache_returnsCachedBook() {}
Podemos melhorar esse nome?
@Test
fun `Call to getByIsbn with ISBN in cache returns cached Book`()
Nota: isso, no android, só funciona com testes unitários. É necessário desabilitar a
verificação por IllegalAndroidIdentifier nas preferências da IDE para o target de
testes unitários.
Que tal...
Material:
Pensamentos Finais
Implementar melhorias é difícil e pode haver riscos.
Antes de qualquer refactoring proteja-se com testes.
Kotlin pode ajudar a melhorar seu código...
Photo by Martins Zemlickis on Unsplash
… mas não fará o trabalho por você! ;)
Material:
“… if you are afraid to change something it is clearly poorly designed.”
- Martin Fowler
Perguntas?
Material:
Eduardo Carrara
@DuCarrara
Obrigado!
github.com/ecarrara-araujo
Material:
Referências
1. Kotlin Home Page
2. The Kotlin Koan
3. Introduction to Kotlin (Google I/O '17)
4. Android Development with Kotlin by Jake Warthon
5. GOTO 2016 • Kotlin - Ready for Production - Hadi Hariri
6. Instrumentation Testing Robots by Jake Warthon
7. Espresso Cheat Sheet
8. Testing on Android Documentation by Android Developers
9. Android Testing Patterns Youtube Playlist
10. The Art of Unit Testing by Roy Osherove
11. Page Objects
12. Android Tests by Goggle Samples
13. Android Testing Templates by Google Samples
14. Mockito Kotlin Lib

Melhorando seu App com Kotlin e Testes

  • 1.
    Material: Melhorando seu Appcom Kotlin e Testes Eduardo Carrara @DuCarrara Android Developer
  • 2.
    Material: Adoramos melhorar nossasaplicações! Para nossos usuários e nós mesmos!
  • 3.
    Material: Photo byCarl Rice on carlrice.io Kotlin esta aí!
  • 4.
    Material: Null Safety Menor verbosidade Integraçãocom Java Properties String Templates Sem Checked Exceptions Expressões Lambda Extension Functions Inline Functions Data Classes
  • 5.
    Material: Functions fun noArgumentsFunction() {/* ... */ } fun withArgumentsFunction(firstArgument: String, secondArgument: Int){ /* ... */ } fun oneLiner() = "No value" fun sum(a: Int, b: Int) = a + b
  • 6.
    Material: Variables // Immutable val variable:Int = 5 val variable2: String val variable3 = 345 // Mutable var variable4 = "Testing" var variable5 = listOf("One", "Two", "Three") var variable6: Long
  • 7.
    Material: Classes open class SimpleClass classComplexClass : SimpleClass() data class DataClass(val immutableValue: Int = 123) object ObjectClass fun justForFun() { val dataClassInstance = DataClass() val dataClassInstance2 = DataClass(immutableValue = 438) print(dataClassInstance.immutableValue) }
  • 8.
    Material: Lambdas // lambda oufunção anônima val lambdaFunction = { a: Int, b: Int -> a + b } val toIntLambda = { value: String -> value.toInt() } // "Useless" Higher Order Function fun map(value: String, transform: (String) -> Int) = transform(value) fun messingAround() { print(map("458", toIntLambda)) print(map("458", { s -> s.toInt() })) }
  • 9.
    Material: Extension Functions fun String.toInt():Int = java.lang.Integer.parseInt(this) fun Int.isNegative(): Boolean = this < 0
  • 10.
  • 11.
    Material: Como começar arefatorar meu app? Qual o estado atual do meu código?
  • 12.
    Material: Minha App Um olharsobre a Arquitetura Feature A Presentation Domain Data Feature B Presentation Domain Data Feature C Presentation Domain Data
  • 13.
    Material: Megazord Monolith Um Olharsobre Arquitetura (Realidade) Component Zord Component Zord Component Zord Component Zord Component Zord Component Zord Component Zord Component Zord
  • 14.
    Material: Vá em frentee quebre umas features por aí... ou Tentar algo mais tranquilo? Photo by The Matrix Movie
  • 15.
    Material: Que tal começar comtestes? Photo by Danielle MacInnes on Unsplash
  • 16.
    Material: Por onde começar? Testesfuncionais com foco no usuário Escolha uma delas para começar Entenda e mapeie as funcionalidades mais importantes Utilize Espresso + Kotlin para automatizar os testes
  • 17.
  • 18.
    Material: ViewMatcher ViewAction ViewAssertion CrashCourse withId withText isDisplayed isVisible is ... click doubleClick longClick pressBack scrollTo ... matches doesNotExist isLeftOf isAbove ...
  • 19.
    Material: Anatomia de umInstrumentation Test @RunWith(AndroidJUnit4::class) class TestClass { @get:Rule var activityInitializationRule = ActivityTestRule<TestActivity>(TestActivity::class.java) @Test fun simpleTest() { /* test stuff */ } } Test Runner Class Definition Initialization Rule Test
  • 20.
    Material: Um teste nãotão simples! @Test fun whenOpened_withOneBookLending_displayBookLendingCorrectly_pureEspresso() { val fakeBook = testDataRule.fakeBook onView(allOf<View>(withId(R.id.book_name_text_view), hasSibling(withText(fakeBook.title))) ).check(matches(isDisplayed())) onView(allOf<View>(withId(R.id.book_author_text_view), hasSibling(withText(fakeBook.authors.joinToString(",")))) ).check(matches(isDisplayed())) } Code: https://goo.gl/RR7DxW
  • 21.
  • 22.
    Material: Instrumentation Testing Robots UmPattern 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)
  • 23.
    Material: Um Teste maisFeliz @Test fun whenOpened_withOneBookLending_displayBookLendingCorrectly() { val fakeBook = testDataRule.fakeBook lentBooks { checkForBookTitle(fakeBook.title) checkForBookAuthors(fakeBook.authors.joinToString(",")) } } Code: https://goo.gl/RR7DxW
  • 24.
    Material: ITR Internals class LentBooksRobot{ fun checkForBookTitle(expectedTitle: String): LentBooksRobot { onView(allOf<View>(withId(R.id.book_name_text_view), hasSibling(withText(expectedTitle))) ).check(ViewAssertions.matches(isDisplayed())) return this } } Code: https://goo.gl/c4K6bo
  • 25.
    Material: ITR Internals class LentBooksRobot{ ... } fun lentBooks(func: LentBooksRobot.() -> Unit) = LentBooksRobot().apply { func() } Code: https://goo.gl/c4K6bo
  • 26.
    Material: ITR - OutroExemplo @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) } ... Code: https://goo.gl/cbMLLA
  • 27.
    Material: Suficiente? Temos nossa "proteção"inicial contra bugs, mas lembre-se ... Maior probabilidade de Test Flakiness Testes instrumentados são mais lentos E agora?
  • 28.
  • 29.
    Material: Parta para oRefactoring Modularize, Isole Componentes, Crie abstrações Escreva testes unitários! Adote padrões de Arquitetura
  • 30.
    Material: Testes Unitários Verificam os"internals" da aplicação Rápidos e Abrangentes Viáveis com baixo acoplamento e em pequenas unidades Utilize JUnit + Mockito (ou outras ferramentas de mocking)
  • 31.
    Material: Exemplo - Vilibra AppData Layer BookRepository Outras Camadas RemoteDataSource LocalDataSource database Serviços Externos
  • 32.
    Material: Testando o BookRepository interfaceBookRepository { fun getByIsbn(isbn: String): Maybe<Book> } class BookCachedRepository( private val bookRemoteDataSource: BookRemoteDataSource, private val bookLocalCache: BookLocalCache ) : BookRepository { override fun getByIsbn(usbn: String): Maybe<Book> { /* ... */ } }
  • 33.
    Material: Testando o BookRepository @RunWith(JUnit4::class) classBookCachedRepositoryTest { @Test fun testingOurRepository() { } } Test Runner Test
  • 34.
    Material: Testando o BookRepository- Mocks @RunWith(MockitoJUnitRunner::class) class BookCachedRepositoryTest { } @Mock lateinit var bookRemoteDataSource: BookRemoteDataSource @Mock lateinit var bookLocalDataSource: BookLocalCache Note: Mock the unmockable: opt-in mocking of final classes/methods
  • 35.
    Material: @RunWith(MockitoJUnitRunner::class) class BookCachedRepositoryTest { /*Mocks Configuration */ } Testando o BookRepository - Tests @Test fun getByIsbn_whenCalled_withExistingIsbnInCache_returnsCachedBook() { //Arrange //Act //Assert } Code: https://goo.gl/Ybh62x
  • 36.
    Material: Testando o BookRepository- Tests @Test fun getByIsbn_whenCalled_withExistingIsbnInCache_returnsCachedBook() { //Arrange //Act & Assert } val fakeBook = prepareFakeBook() whenever(bookLocalDataSource[fakeBook.isbn10]) .thenReturn(Maybe.just(fakeBook)) val bookCachedRepository = BookCachedRepository(bookRemoteDataSource, bookLocalDataSource) bookCachedRepository.getByIsbn(fakeBook.isbn10) .test() .assertValue(fakeBook) Code: https://goo.gl/Ybh62x
  • 37.
    Material: Último Truque! @Test fun getByIsbn_whenCalled_withExistingIsbnInCache_returnsCachedBook(){} Podemos melhorar esse nome? @Test fun `Call to getByIsbn with ISBN in cache returns cached Book`() Nota: isso, no android, só funciona com testes unitários. É necessário desabilitar a verificação por IllegalAndroidIdentifier nas preferências da IDE para o target de testes unitários. Que tal...
  • 38.
    Material: Pensamentos Finais Implementar melhoriasé difícil e pode haver riscos. Antes de qualquer refactoring proteja-se com testes. Kotlin pode ajudar a melhorar seu código... Photo by Martins Zemlickis on Unsplash … mas não fará o trabalho por você! ;)
  • 39.
    Material: “… if youare afraid to change something it is clearly poorly designed.” - Martin Fowler Perguntas?
  • 40.
  • 41.
    Material: Referências 1. Kotlin HomePage 2. The Kotlin Koan 3. Introduction to Kotlin (Google I/O '17) 4. Android Development with Kotlin by Jake Warthon 5. GOTO 2016 • Kotlin - Ready for Production - Hadi Hariri 6. Instrumentation Testing Robots by Jake Warthon 7. Espresso Cheat Sheet 8. Testing on Android Documentation by Android Developers 9. Android Testing Patterns Youtube Playlist 10. The Art of Unit Testing by Roy Osherove 11. Page Objects 12. Android Tests by Goggle Samples 13. Android Testing Templates by Google Samples 14. Mockito Kotlin Lib