Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Start Speking It
Search
Fábio Carballo
January 09, 2018
Technology
0
130
Start Speking It
This decks is about how we use Spek instead of pure JUnit to test our Android app.
Fábio Carballo
January 09, 2018
Tweet
Share
More Decks by Fábio Carballo
See All by Fábio Carballo
Kickstarting our Design System
fabiocarballo
2
390
Tackling Android at Scale
fabiocarballo
9
970
Improve your tests using Kotlin.
fabiocarballo
1
120
What I've Learned as an Inexperienced Developer
fabiocarballo
0
120
Testing with Kotlin (using Spek and Mockito)
fabiocarballo
0
1k
andKotlin
fabiocarballo
0
140
Other Decks in Technology
See All in Technology
「活動」は激変する。「ベース」は変わらない ~ 4つの軸で捉える_AI時代ソフトウェア開発マネジメント
sentokun
0
130
Embeddings : Symfony AI en pratique
lyrixx
0
420
FastMCP OAuth Proxy with Cognito
hironobuiga
3
220
Oracle AI Database@Google Cloud:サービス概要のご紹介
oracle4engineer
PRO
5
1.2k
Oracle Cloud Infrastructure:2026年3月度サービス・アップデート
oracle4engineer
PRO
0
180
Tour of Agent Protocols: MCP, A2A, AG-UI, A2UI with ADK
meteatamel
0
100
SSoT(Single Source of Truth)で「壊して再生」する設計
kawauso
2
400
VSCode中心だった自分がターミナル沼に入門した話
sanogemaru
0
840
FASTでAIエージェントを作りまくろう!
yukiogawa
4
160
CloudFrontのHost Header転送設定でパケットの中身はどう変わるのか?
nagisa53
1
220
Amazon Qはアマコネで頑張っています〜 Amazon Q in Connectについて〜
yama3133
1
150
AI時代のIssue駆動開発のススメ
moongift
PRO
0
290
Featured
See All Featured
How to build a perfect <img>
jonoalderson
1
5.3k
Building an army of robots
kneath
306
46k
How to train your dragon (web standard)
notwaldorf
97
6.6k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.2k
WENDY [Excerpt]
tessaabrams
9
37k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.6k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
780
It's Worth the Effort
3n
188
29k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.8k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
230
Game over? The fight for quality and originality in the time of robots
wayneb77
1
150
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.6k
Transcript
Start Speking it. Rui Gonçalo @rmgoncalo Fábio Carballo @fabiocarballo
None
JUnit
None
None
Test Actions Groups
Test • it
Test it(“should be true”) { assertTrue(true) }
Groups • group
Groups group(“a testing group”) { group(“a nested group”) { }
}
Groups group(“a testing group”) { group(“a nested group”) { }
}
Groups describe(“a testing group”) { group(“a nested group”) { }
}
Groups context(“a testing group”) { group(“a nested group”) { }
}
Groups given(“a testing group”) { group(“a nested group”) { }
}
Groups fun SpecBody.context(description: String, body: SpecBody.() -> Unit) { group("context
$description", body = body) } fun SpecBody.given(description: String, body: SpecBody.() -> Unit) { group(“given $description", body = body) } fun SpecBody.describe(description: String, body: SpecBody.() -> Unit) { group(“describe $description", body = body) }
Actions • on
Actions on(“action that triggers the test”) { tested.actionThatTriggersIt() it(“should do
X by Y”) { … } }
object SimpleSpec: Spek({ describe("a bakery") { val calculator = SampleCalculator()
on(“bake bread") { val breads = bakery.mix(“salt”, “margarine” , “flour”) it(“should return some bread") { assertTrue(breads.isNotEmpty() } }
object SimpleSpec: Spek({ describe("a bakery") { val bakery = Bakery()
on(“mixing bread ingredients”) { val breads = bakery.mix(“salt”, “margarine”, “flour”) it(“should return some bread") { assertTrue(breads.isNotEmpty() } } }
None
checkPermission GRANT DENY requestPermission onPermissionGranted onPermissionDenied getDistances getDistances showError
class Presenter( permissionsManager: PermissionsManager, distancesProvider: DistancesProvider, view: View) { }
interface PermissionsManager { fun checkPermission(): Observable<Boolean> fun requestPermissions(): Observable<Boolean> }
class Presenter( permissionsManager: PermissionsManager, distancesProvider: DistancesProvider, view: View) { }
interface DistancesProvider { fun getDistances() : Observable<Int> } class Presenter(
permissionsManager: PermissionsManager, distancesProvider: DistancesProvider, view: View) { } interface PermissionsManager { fun checkPermission(): Observable<Boolean> fun requestPermissions(): Observable<Boolean> }
interface View { fun showDistance(distance: Int) fun showError() } interface
PermissionsManager { fun checkPermission(): Observable<Boolean> fun requestPermissions(): Observable<Boolean> } class Presenter( permissionsManager: PermissionsManager, distancesProvider: DistancesProvider, view: View) { } interface DistancesProvider { fun getDistances() : Observable<Int> }
permissionsManager.checkPermission() GRANT DENY permissionsManager.requestPermission() GRANT DENY distancesProvider.getDistances() view.showError() distancesProvider.getDistances()
permissionsManager.checkPermission() GRANT DENY permissionsManager.requestPermission() GRANT DENY distancesProvider.getDistances() view.showError() distancesProvider.getDistances()
checkPermission GRANT getDistances
checkPermission GRANT getDistances @Test fun when_check_permission_and_permission_is_granted_should_get_distance() { … }
@Test fun when_check_permission_and_permission_is_granted_should_get_distance() { whenever(permissionsManager.checkPermission()).thenReturn(Observable.just(true)) } checkPermission GRANT getDistances
@Test fun when_check_permission_and_permission_is_granted_should_get_distance() { whenever(permissionsManager.checkPermission()).thenReturn(Observable.just(true)) presenter.start() verify(distancesProvider).getDistance() } checkPermission GRANT
getDistances
checkPermission DENY requestPermission onPermissionGranted getDistances
whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) checkPermission DENY requestPermission onPermissionGranted getDistances
whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) whenever(permissionsManager.requestPermission()) .thenReturn(Observable.just(true)) checkPermission DENY requestPermission onPermissionGranted getDistances
whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) whenever(permissionsManager.requestPermission()) .thenReturn(Observable.just(true)) presenter.start() verify(permissionsManager).requestPermission() verify(view).getDistances() checkPermission DENY requestPermission
onPermissionGranted getDistances
checkPermission DENY requestPermission onPermissionDenied showError
whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) whenever(permissionsManager.requestPermission()) .thenReturn(Observable.just(false)) checkPermission DENY requestPermission onPermissionDenied showError
whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) whenever(permissionsManager.requestPermission()) .thenReturn(Observable.just(false)) checkPermission DENY requestPermission onPermissionDenied showError
whenever(permissionsManager.checkPermission()) .thenReturn(Single.just(false)) whenever(permissionsManager.requestPermission()) .thenReturn(Single.just(false)) presenter.start() verify(permissionsManager).requestPermission() verify(view).showError() checkPermission DENY requestPermission
onPermissionDenied showError
checkPermission GRANT getDistances checkPermission DENY requestPermission onPermissionGranted getDistances checkPermission DENY
requestPermission onPermissionDenied showError
checkPermission GRANT getDistances checkPermission DENY requestPermission onPermissionGranted getDistances checkPermission DENY
requestPermission onPermissionDenied showError
checkPermission GRANT getDistances checkPermission DENY requestPermission onPermissionGranted getDistances checkPermission DENY
requestPermission onPermissionDenied showError
Spek
checkPermission GRANT getDistances checkPermission DENY requestPermission onPermissionGranted getDistances checkPermission DENY
requestPermission onPermissionDenied showError
checkPermission GRANT getDistances
describe(“check permission”) { context("permission is granted”) { it("should get distance”)
{ } } } checkPermission GRANT getDistances
describe(“check permission”) { context("permission is granted”) { it("should get distance”)
{ } } } checkPermission GRANT getDistances
describe(“check permission”) { context("permission is granted”) { it("should get distances”)
{ } } } checkPermission GRANT getDistances
describe(“check permission”) { context("permission is granted”) { it("should get distances”)
{ verify(distancesProvider).getDistances() } } } checkPermission GRANT getDistances
describe(“check permission”) { context("permission is granted”) { it("should get distances”)
{ verify(distancesProvider).getDistances() } } context("permission is denied”) { it(“should request permissions”) { verify(permissionsManager).requestPermissions() } } } checkPermission GRANT getDistances DENY requestPermission
describe(“check permission”) { … context("permission is denied”) { it(“should request
permissions”) { … } given(“a permission request”) { on(“permission granted”) { it(“should get distance”) { … } } } } } checkPermission GRANT getDistances DENY requestPermission onPermissionGranted
describe(“check permission”) { … context("permission is denied”) { it(“should request
permissions”) { … } given(“a permission request”) { on(“permission granted”) { it(“should get distances”) { } } } } } checkPermission GRANT getDistances DENY requestPermission onPermissionGranted getDistances
describe(“check permission”) { … context("permission is denied”) { it(“should request
permissions”) { … } given(“a permission request”) { on(“permission granted”) { it(“should get distances”) { verify(distancesProvider).getDistances() } } } } } checkPermission GRANT getDistances DENY requestPermission onPermissionGranted getDistances
checkPermission GRANT getDistances DENY requestPermission onPermissionGranted getDistances onPermissionDenied showError describe(“check
permission”) { context("permission is denied”) { given(“a permission request”) { on(“permission granted”) { it(“should get distances”) { … } } on(“permission denied”) { it(“should show error”) { verify(view).showError() } } } } }
describe(“check permission”) { context("permission is granted”) it(“should get distances”) {
… } context(“permission is denied”) { it(“should request permission”) { … } given(“a permission request”) { on(“permission granted”) it(“should get distances”) { … } on(“permission denied”) it(“should show error”) { … } } } checkPermission GRANT getDistances DENY requestPermission onPermissionGranted getDistances onPermissionDenied showError
How to setup/teardown ?
beforeEachTest { } afterEachTest { }
describe(“check permission”) { context("permission is granted”) { it(“should get distances”)
{ … } } context(“permission is denied”) { it(“should request permission”) { … } given(“a permission request”) { on(“permission granted”) it(“should get distances”) { … } on(“permission denied”) it(“should show error”) { … } } }
describe(“check permission”) { context("permission is granted”) { it(“should get distances”)
{ … } } context(“permission is denied”) { it(“should request permission”) { … } given(“a permission request”) { on(“permission granted”) it(“should get distances”) { … } on(“permission denied”) it(“should show error”) { … } } }
describe(“check permission”) { context("permission is granted”) { it(“should get distances”)
{ … } } context(“permission is denied”) { it(“should request permission”) { … } } }
describe(“check permission”) { context("permission is granted”) { beforeEachTest { whenever(permissionsManager.checkPermission())
.thenReturn(Observable.just(true)) tested.start() } it(“should get distances”) { … } } context(“permission is denied”) { it(“should request permission”) { … } } }
describe(“check permission”) { context("permission is granted”) { it(“should get distances”)
{ … } } context(“permission is denied”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Single.just(false)) tested.start() } it(“should request permission”) { … } } }
describe(“check permission”) { context("permission is granted”) { it(“should get distances”)
{ … } } context(“permission is denied”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) tested.start() } it(“should request permission”) { … } } }
describe(“check permission”) { context("permission is granted”) { } context(“permission is
denied”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) tested.start() } } }
describe(“check permission”) { context("permission is granted”) { beforeEachTest { whenever(permissionsManager.checkPermission())
.thenReturn(Observable.just(true)) tested.start() } } context(“permission is denied”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) tested.start() } } }
describe(“check permission”) { context("permission is granted”) { beforeEachTest { whenever(permissionsManager.checkPermission())
.thenReturn(Observable.just(true)) tested.start() } } context(“permission is denied”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) tested.start() } } }
describe(“start”) { context("permission is granted”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(true))
tested.start() } } context(“permission is denied”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) tested.start() } } }
describe(“start”) { beforeEachTest { tested.start() } context("permission is granted”) {
beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(true)) } } context(“permission is denied”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) } } }
describe(“start”) { beforeEachTest { tested.start() } it(“should check permission”) {
verify(permissionsManager).checkPermission() } context("permission is granted”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(true)) } } context(“permission is denied”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) } } }
describe(“start”) { beforeEachTest { tested.start() } it(“should check permission”) {…}
context("permission is granted”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(true)) } } context(“permission is denied”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) } } }
describe(“start”) { beforeEachTest { tested.start() } it(“should check permission”) {…}
context("permission is granted”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(true)) } } context(“permission is denied”) { beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(false)) } } }
beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(true)) } describe(“start”) { beforeEachTest { tested.start()
} it(“should check permission”) {…} context("permission is granted”) { } context(“permission is denied”) { } }
beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(true)) } describe(“start”) { beforeEachTest { tested.start()
} it(“should check permission”) {…} context("permission is granted”) { } context(“permission is denied”) { } }
beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(Observable.just(true)) } describe(“start”) { beforeEachTest { tested.start()
} it(“should check permission”) {…} context("permission is granted”) { } context(“permission is denied”) { it(“should request permission”) { … } } }
beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(____________) } describe(“start”) { beforeEachTest { tested.start()
} it(“should check permission”) {…} context("permission is granted”) { } context(“permission is denied”) { it(“should request permission”) { … } } }
val permissionPubSub: PublishSubject<Boolean> = PublishSubject.create() beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(permissionPubSub) }
describe(“start”) { beforeEachTest { tested.start() } it(“should check permission”) {…} context("permission is granted”) { } context(“permission is denied”) { it(“should request permission”) { … } } }
val permissionPubSub: PublishSubject<Boolean> = PublishSubject.create() beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(permissionPubSub) }
describe(“start”) { beforeEachTest { tested.start() } it(“should check permission”) {…} context("permission is granted”) { } context(“permission is denied”) { it(“should request permission”) { … } } }
val permissionPubSub: PublishSubject<Boolean> = PublishSubject.create() beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(permissionPubSub) }
describe(“start”) { beforeEachTest { tested.start() } it(“should check permission”) {…} context("permission is granted”) { } context(“permission is denied”) { beforeEachTest { permissionPubSub.onNext(false) } it(“should request permission”) { … } } }
val permissionPubSub: PublishSubject<Boolean> = PublishSubject.create() beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(permissionPubSub) }
describe(“start”) { beforeEachTest { tested.start() } it(“should check permission”) {…} context("permission is granted”) { beforeEachTest { permissionPubSub.onNext(true) } it(“should get distances”) { … } } context(“permission is denied”) { beforeEachTest { permissionPubSub.onNext(false) } it(“should request permission”) { … } } }
beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(permissionPubSub) whenever(permissionsManager.requestPermission()) .thenReturn(requestPubSub) } describe(“start”) { beforeEachTest
{ tested.start() } it(“should check permission”) {…} context("permission is granted”) { beforeEachTest { permissionPubSub.onNext(true) } it(“should get distances”) { … } } context(“permission is denied”) { beforeEachTest { permissionPubSub.onNext(false) } it(“should request permission”) { … } } }
beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(permissionPubSub) whenever(permissionsManager.requestPermission()) .thenReturn(requestPubSub) } describe(“start”) { beforeEachTest
{ tested.start() } it(“should check permission”) {…} context("permission is granted”) { beforeEachTest { permissionPubSub.onNext(true) } it(“should get distances”) { … } } context(“permission is denied”) { beforeEachTest { permissionPubSub.onNext(false) } it(“should request permission”) { … } } }
beforeEachTest { whenever(permissionsManager.checkPermission()) .thenReturn(permissionPubSub) whenever(permissionsManager.requestPermission()) .thenReturn(requestPubSub) } describe(“start”) { context(“permission
is denied”) { given(“a permission request”) { on(“permission granted”) { requestPubSub.onNext(true) it(“should get distances”) { … } } on(“permission denied”) { requestPubSub.onNext(false) it(“should show error”) { … } } } } }
None
None
None
Cheat Sheet of Getting into Spek
org.mockito.exceptions.base.MockitoException: Cannot mock/spy class com.package.YourClass Mockito cannot mock/spy because :
- final class
mock-maker-inline
Mockito.`when`(mapper.call(Mockito.any())).thenReturn(Entity()) fun call(a: A): B
Mockito.any() must not be null java.lang.IllegalStateException: Mockito.any() must not be
null
Mockito.`when`(mapper.call(Mockito.any())).thenReturn(B()) fun call(a: A): B null
None
fun SpecBody.rxGiven(description: String, body: SpecBody.() -> Unit) { val immediate
= object : Scheduler() { override fun scheduleDirect(run: Runnable, delay: Long, unit: TimeUnit): Disposable { return super.scheduleDirect(run, 0, unit) } override fun createWorker(): Scheduler.Worker { return ExecutorScheduler.ExecutorWorker(Runnable::run) } } beforeEachTest { RxJavaPlugins.setInitIoSchedulerHandler{ immediate } RxJavaPlugins.setInitComputationSchedulerHandler{ immediate } RxJavaPlugins.setInitNewThreadSchedulerHandler{ immediate } RxJavaPlugins.setInitSingleSchedulerHandler{ immediate } RxAndroidPlugins.setInitMainThreadSchedulerHandler { scheduler -> immediate } } given(description, body = body) afterEachTest { RxJavaPlugins.reset() RxAndroidPlugins.reset() } }
fun SpecBody.rxGiven(description: String, body: SpecBody.() -> Unit) { val immediate
= object : Scheduler() { override fun scheduleDirect(run: Runnable, delay: Long, unit: TimeUnit): Disposable { return super.scheduleDirect(run, 0, unit) } override fun createWorker(): Scheduler.Worker { return ExecutorScheduler.ExecutorWorker(Runnable::run) } } beforeEachTest { RxJavaPlugins.setInitIoSchedulerHandler{ immediate } RxJavaPlugins.setInitComputationSchedulerHandler{ immediate } RxJavaPlugins.setInitNewThreadSchedulerHandler{ immediate } RxJavaPlugins.setInitSingleSchedulerHandler{ immediate } RxAndroidPlugins.setInitMainThreadSchedulerHandler { scheduler -> immediate } } given(description, body = body) afterEachTest { RxJavaPlugins.reset() RxAndroidPlugins.reset() } }
fun SpecBody.rxGiven(description: String, body: SpecBody.() -> Unit) { val immediate
= object : Scheduler() { override fun scheduleDirect(run: Runnable, delay: Long, unit: TimeUnit): Disposable { return super.scheduleDirect(run, 0, unit) } override fun createWorker(): Scheduler.Worker { return ExecutorScheduler.ExecutorWorker(Runnable::run) } } beforeEachTest { RxJavaPlugins.setInitIoSchedulerHandler{ immediate } RxJavaPlugins.setInitComputationSchedulerHandler{ immediate } RxJavaPlugins.setInitNewThreadSchedulerHandler{ immediate } RxJavaPlugins.setInitSingleSchedulerHandler{ immediate } RxAndroidPlugins.setInitMainThreadSchedulerHandler { scheduler -> immediate } } given(description, body = body) afterEachTest { RxJavaPlugins.reset() RxAndroidPlugins.reset() } }
fun SpecBody.rxGiven(description: String, body: SpecBody.() -> Unit) { val immediate
= object : Scheduler() { override fun scheduleDirect(run: Runnable, delay: Long, unit: TimeUnit): Disposable { return super.scheduleDirect(run, 0, unit) } override fun createWorker(): Scheduler.Worker { return ExecutorScheduler.ExecutorWorker(Runnable::run) } } beforeEachTest { RxJavaPlugins.setInitIoSchedulerHandler{ immediate } RxJavaPlugins.setInitComputationSchedulerHandler{ immediate } RxJavaPlugins.setInitNewThreadSchedulerHandler{ immediate } RxJavaPlugins.setInitSingleSchedulerHandler{ immediate } RxAndroidPlugins.setInitMainThreadSchedulerHandler { scheduler -> immediate } } given(description, body = body) afterEachTest { RxJavaPlugins.reset() RxAndroidPlugins.reset() } }
fun SpecBody.rxGiven(description: String, body: SpecBody.() -> Unit) { beforeEachTest {
ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() { override fun executeOnDiskIO(runnable: Runnable) { runnable.run() } override fun postToMainThread(runnable: Runnable) { runnable.run() } override fun isMainThread(): Boolean { return true } }) } given(description, body = body) afterEachTest { ArchTaskExecutor.getInstance().setDelegate(null) } }
fun SpecBody.rxGiven(description: String, body: SpecBody.() -> Unit) { beforeEachTest {
ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() { override fun executeOnDiskIO(runnable: Runnable) { runnable.run() } override fun postToMainThread(runnable: Runnable) { runnable.run() } override fun isMainThread(): Boolean { return true } }) } given(description, body = body) afterEachTest { ArchTaskExecutor.getInstance().setDelegate(null) } }
None
None
Thank you Rui Gonçalo @rmgoncalo Fábio Carballo @fabiocarballo