1
Uma abordagem de testes
instrumentados usando MockK, Koin
e Robot Pattern
Lucas Conceição
© 2019 ThoughtWorks
Lucas Conceição
Senior Android consultant
11 anos codando
4 anos codando para Android
2 anos codando em Kotlin
7 meses na ThoughtWorks
2© 2019 ThoughtWorks
PROGRAMAÇÃO
3
TESTES
INSTRUMENTADOS
ROBOT
PATTERN
MOCKK
© 2019 ThoughtWorks
CODEKOIN
O quê, por quê e como
Testes instrumentados
4© 2019 ThoughtWorks
5© 2019 ThoughtWorks
São feitos com
Espresso
Biblioteca para interação com
interfaces.
@Test
fun checkTheAnswer_toLife_theUniverse_andEverything() {
onView(withText("4")).perform(click())
onView(withText("0")).perform(click())
onView(withText("+")).perform(click())
onView(withText("2")).perform(click())
onView(withText("=")).perform(click())
onView(withId(R.id.result))
.check(matches(withText("42")))
}
6© 2019 ThoughtWorks
Motivação
Testes instrumentados:
-Envolvem código de camadas diferentes do app
E por que falar disso?
7© 2019 ThoughtWorks
Motivação
Testes instrumentados:
-Envolvem código de camadas diferentes do app
-Possuem um custo computacional alto
E por que falar disso?
8© 2019 ThoughtWorks
Motivação
Testes instrumentados:
-Envolvem código de camadas diferentes do app
-Possuem um custo computacional alto
-Podem ser visto/utilizado por pessoas que não necessariamente têm contexto de
Android.
E por que falar disso?
9© 2019 ThoughtWorks
Separe o "o quê" do "como"
Robot Pattern
10© 2019 ThoughtWorks
“We're programmers, we are lazy. We want the
most efficient thing that minimizes the amount of
work that we have to do.”
- Clarice Lispector
11© 2019 ThoughtWorks
“We're programmers, we are lazy. We want the
most efficient thing that minimizes the amount of
work that we have to do.”
- Clarice Lispector Jake Wharton
12© 2019 ThoughtWorks
// O fluxo que precisa ser testado
@Test
fun
checkTheAnswer_toLife_theUniverse_andEverything() {
typeText("40")
sumWith()
typeText("2")
askResult()
checkResultIs("42")
}
// Como testar esse fluxo
fun typeText(amount: String) {
for (index in amount.indices) {
onView(withText(amount[index]))
.perform(click())
}
}
fun sumWith() =
onView(withText("+")).perform(click())
fun askResult() =
onView(withText("=")).perform(click())
fun checkResultIs(result: String) =
onView(withId(R.id.result))
.check(matches(withText(result)))
13© 2019 ThoughtWorks
Dá pra melhorar
// O fluxo que precisa ser testado
@Test
fun checkTheAnswer_toLife_theUniverse_andEverything() {
openCalculator {
typeText("40")
sumWith()
typeText("2")
} askResult {
checkResultIs("42")
}
}
Aproveitando as language features do Kotlin dá pra ficar de um jeito mais legível
14© 2019 ThoughtWorks
Crie mocks com facilidade
MockK
15© 2019 ThoughtWorks
MockK
@Test
fun whenLightIsGreen_driverBehavesAccordingly() {
val trafficLight = TrafficLight().apply { color = Color.RED }
val mockedCar: Car = mockk()
every { mockedCar.honk() } returns Unit
val driver = Driver()
driver.enterCar(mockedCar)
driver.observe(trafficLight)
trafficLight.notify(Color.GREEN)
verify { mockedCar.honk() }
}
Como usar
16© 2019 ThoughtWorks
MockK
@Test
fun suvDrivers_areKindOfJerks() {
// inicializa trafficLight e mockedCar
val honkIntensity = slot<Int>()
every { mockedCar.type } returns CarType.SUV
every { mockedCar.honk(capture(honkIntensity)) } returns Unit
// driver é criado, entra no mockedCar e observa a trafficLight
trafficLight.notify(Color.GREEN)
assertThat(honkIntensity.isCaptured).isTrue()
assertThat(honkIntensity.captured).isAtLeast(92)
}
Teste os argumentos passados utilizando Slots
17© 2019 ThoughtWorks
Injeção de dependência leve e fácil
Koin
18© 2019 ThoughtWorks
Injeção de dependência
// A própria classe cria suas dependências
class CarViewModel : ViewModel() {
private val repository: CarRepository
constructor() {
repository = CarRepository()
}
}
19© 2019 ThoughtWorks
// Quem vai usar o objeto decide
// o que passar para ele
class CarViewModel : ViewModel() {
private val repository: CarRepository
constructor(repository: CarRepository) {
this.repository = repository
}
}
Injeção de dependência
class CarViewModel : ViewModel(), KoinComponent {
private val repository: CarRepository by inject()
fun loremIpsum() {
repository.someMethod()
}
}
Com Koin
20© 2019 ThoughtWorks
class CarViewModel : ViewModel(), KoinComponent {
fun onlyMethodThatNeedsTheRepositoryInstance() {
val repository: CarRepository = get()
repository.someMethod()
}
}
Koin
val storageModule = module {
single {
Room.databaseBuilder(
get(),
AppDatabase::class.java,
"your-database"
).build()
}
}
val appModule = module {
single { CarLocalDataSource(get()) }
factory { CarRepository(get()) }
}
Como configurar
21© 2019 ThoughtWorks
// Na sua classe Application
startKoin {
modules(listOf(
appModule,
storageModule /*, networkModule etc. */
))
}
Show me the code
22© 2019 ThoughtWorks
Dúvidas, sugestões ou feedbacks?
23© 2019 ThoughtWorks
Obrigado a todas
24
LUCAS CONCEIÇÃO
lucas.conceicao@thoughtworks.com | thoughtworks.com
© 2019 ThoughtWorks

Mais conteúdo relacionado

PDF
Melhorando seu App com Kotlin e Testes
PDF
TDC2016POA | Trilha Android - Testes no Android
PDF
TDC2016POA | Trilha Android - Testes no Android
PDF
Android: testes automatizados e TDD
PDF
Kotlin first
ODP
Palestra Mocks - AgileBrazil 2010
PDF
Android DevConference - Indo além com automação de testes de apps Android
PDF
Indo além com Automação de Testes de Apps Android
Melhorando seu App com Kotlin e Testes
TDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no Android
Android: testes automatizados e TDD
Kotlin first
Palestra Mocks - AgileBrazil 2010
Android DevConference - Indo além com automação de testes de apps Android
Indo além com Automação de Testes de Apps Android

Último (17)

PPT
Conceitos básicos de Redes Neurais Artificiais
PDF
Jira Software projetos completos com scrum
PDF
Visão geral da SAP, SAP01 Col18, Introdução sistema SAP,
PDF
Customizing básico em SAP Extended Warehouse Management, EWM110 Col26
PPTX
Tipos de servidor em redes de computador.pptx
PPTX
Proposta de Implementação de uma Rede de Computador Cabeada.pptx
PDF
eBook - GUIA DE CONSULTA RAPIDA EM ROTEADORES E SWITCHES CISCO - VOL I.pdf
PPTX
3b - Bradesco Lean Agile Training Plan - Ritos Operacionais (1).pptx
PDF
SEMINÁRIO DE IHC - A interface Homem-Máquina
PDF
Processos no SAP Extended Warehouse Management, EWM100 Col26
PPTX
Aula 9 - Funções em Python (Introdução à Ciência da Computação)
PDF
Aula 9 - Funções 202yttvrcrg5-1.pptx.pdf
PDF
Banco de Dados 2atualização de Banco de d
PPTX
ccursoammaiacursoammaiacursoammaia123456
PDF
Processamento da remessa no SAP ERP, SCM610 Col15
PPTX
Analise Estatica de Compiladores para criar uma nova LP
PPT
Aula de Engenharia de Software principais caracteristicas
Conceitos básicos de Redes Neurais Artificiais
Jira Software projetos completos com scrum
Visão geral da SAP, SAP01 Col18, Introdução sistema SAP,
Customizing básico em SAP Extended Warehouse Management, EWM110 Col26
Tipos de servidor em redes de computador.pptx
Proposta de Implementação de uma Rede de Computador Cabeada.pptx
eBook - GUIA DE CONSULTA RAPIDA EM ROTEADORES E SWITCHES CISCO - VOL I.pdf
3b - Bradesco Lean Agile Training Plan - Ritos Operacionais (1).pptx
SEMINÁRIO DE IHC - A interface Homem-Máquina
Processos no SAP Extended Warehouse Management, EWM100 Col26
Aula 9 - Funções em Python (Introdução à Ciência da Computação)
Aula 9 - Funções 202yttvrcrg5-1.pptx.pdf
Banco de Dados 2atualização de Banco de d
ccursoammaiacursoammaiacursoammaia123456
Processamento da remessa no SAP ERP, SCM610 Col15
Analise Estatica de Compiladores para criar uma nova LP
Aula de Engenharia de Software principais caracteristicas
Anúncio
Anúncio

Uma abordagem de testes instrumentados usando MockK, Koin e Robot Pattern

  • 1. 1 Uma abordagem de testes instrumentados usando MockK, Koin e Robot Pattern Lucas Conceição © 2019 ThoughtWorks
  • 2. Lucas Conceição Senior Android consultant 11 anos codando 4 anos codando para Android 2 anos codando em Kotlin 7 meses na ThoughtWorks 2© 2019 ThoughtWorks
  • 4. O quê, por quê e como Testes instrumentados 4© 2019 ThoughtWorks
  • 6. São feitos com Espresso Biblioteca para interação com interfaces. @Test fun checkTheAnswer_toLife_theUniverse_andEverything() { onView(withText("4")).perform(click()) onView(withText("0")).perform(click()) onView(withText("+")).perform(click()) onView(withText("2")).perform(click()) onView(withText("=")).perform(click()) onView(withId(R.id.result)) .check(matches(withText("42"))) } 6© 2019 ThoughtWorks
  • 7. Motivação Testes instrumentados: -Envolvem código de camadas diferentes do app E por que falar disso? 7© 2019 ThoughtWorks
  • 8. Motivação Testes instrumentados: -Envolvem código de camadas diferentes do app -Possuem um custo computacional alto E por que falar disso? 8© 2019 ThoughtWorks
  • 9. Motivação Testes instrumentados: -Envolvem código de camadas diferentes do app -Possuem um custo computacional alto -Podem ser visto/utilizado por pessoas que não necessariamente têm contexto de Android. E por que falar disso? 9© 2019 ThoughtWorks
  • 10. Separe o "o quê" do "como" Robot Pattern 10© 2019 ThoughtWorks
  • 11. “We're programmers, we are lazy. We want the most efficient thing that minimizes the amount of work that we have to do.” - Clarice Lispector 11© 2019 ThoughtWorks
  • 12. “We're programmers, we are lazy. We want the most efficient thing that minimizes the amount of work that we have to do.” - Clarice Lispector Jake Wharton 12© 2019 ThoughtWorks
  • 13. // O fluxo que precisa ser testado @Test fun checkTheAnswer_toLife_theUniverse_andEverything() { typeText("40") sumWith() typeText("2") askResult() checkResultIs("42") } // Como testar esse fluxo fun typeText(amount: String) { for (index in amount.indices) { onView(withText(amount[index])) .perform(click()) } } fun sumWith() = onView(withText("+")).perform(click()) fun askResult() = onView(withText("=")).perform(click()) fun checkResultIs(result: String) = onView(withId(R.id.result)) .check(matches(withText(result))) 13© 2019 ThoughtWorks
  • 14. Dá pra melhorar // O fluxo que precisa ser testado @Test fun checkTheAnswer_toLife_theUniverse_andEverything() { openCalculator { typeText("40") sumWith() typeText("2") } askResult { checkResultIs("42") } } Aproveitando as language features do Kotlin dá pra ficar de um jeito mais legível 14© 2019 ThoughtWorks
  • 15. Crie mocks com facilidade MockK 15© 2019 ThoughtWorks
  • 16. MockK @Test fun whenLightIsGreen_driverBehavesAccordingly() { val trafficLight = TrafficLight().apply { color = Color.RED } val mockedCar: Car = mockk() every { mockedCar.honk() } returns Unit val driver = Driver() driver.enterCar(mockedCar) driver.observe(trafficLight) trafficLight.notify(Color.GREEN) verify { mockedCar.honk() } } Como usar 16© 2019 ThoughtWorks
  • 17. MockK @Test fun suvDrivers_areKindOfJerks() { // inicializa trafficLight e mockedCar val honkIntensity = slot<Int>() every { mockedCar.type } returns CarType.SUV every { mockedCar.honk(capture(honkIntensity)) } returns Unit // driver é criado, entra no mockedCar e observa a trafficLight trafficLight.notify(Color.GREEN) assertThat(honkIntensity.isCaptured).isTrue() assertThat(honkIntensity.captured).isAtLeast(92) } Teste os argumentos passados utilizando Slots 17© 2019 ThoughtWorks
  • 18. Injeção de dependência leve e fácil Koin 18© 2019 ThoughtWorks
  • 19. Injeção de dependência // A própria classe cria suas dependências class CarViewModel : ViewModel() { private val repository: CarRepository constructor() { repository = CarRepository() } } 19© 2019 ThoughtWorks // Quem vai usar o objeto decide // o que passar para ele class CarViewModel : ViewModel() { private val repository: CarRepository constructor(repository: CarRepository) { this.repository = repository } }
  • 20. Injeção de dependência class CarViewModel : ViewModel(), KoinComponent { private val repository: CarRepository by inject() fun loremIpsum() { repository.someMethod() } } Com Koin 20© 2019 ThoughtWorks class CarViewModel : ViewModel(), KoinComponent { fun onlyMethodThatNeedsTheRepositoryInstance() { val repository: CarRepository = get() repository.someMethod() } }
  • 21. Koin val storageModule = module { single { Room.databaseBuilder( get(), AppDatabase::class.java, "your-database" ).build() } } val appModule = module { single { CarLocalDataSource(get()) } factory { CarRepository(get()) } } Como configurar 21© 2019 ThoughtWorks // Na sua classe Application startKoin { modules(listOf( appModule, storageModule /*, networkModule etc. */ )) }
  • 22. Show me the code 22© 2019 ThoughtWorks
  • 23. Dúvidas, sugestões ou feedbacks? 23© 2019 ThoughtWorks
  • 24. Obrigado a todas 24 LUCAS CONCEIÇÃO lucas.conceicao@thoughtworks.com | thoughtworks.com © 2019 ThoughtWorks