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
88
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
350
Tackling Android at Scale
fabiocarballo
9
740
Improve your tests using Kotlin.
fabiocarballo
1
78
What I've Learned as an Inexperienced Developer
fabiocarballo
0
100
Testing with Kotlin (using Spek and Mockito)
fabiocarballo
0
910
andKotlin
fabiocarballo
0
130
Other Decks in Technology
See All in Technology
ノーコードデータ分析ツールで体験する時系列データ分析超入門
negi111111
0
410
Platform Engineering for Software Developers and Architects
syntasso
1
520
信頼性に挑む中で拡張できる・得られる1人のスキルセットとは?
ken5scal
2
530
Amplify Gen2 Deep Dive / バックエンドの型をいかにしてフロントエンドへ伝えるか #TSKaigi #TSKaigiKansai #AWSAmplifyJP
tacck
PRO
0
370
100 名超が参加した日経グループ横断の競技型 AWS 学習イベント「Nikkei Group AWS GameDay」の紹介/mediajaws202411
nikkei_engineer_recruiting
1
170
オープンソースAIとは何か? --「オープンソースAIの定義 v1.0」詳細解説
shujisado
7
810
Incident Response Practices: Waroom's Features and Future Challenges
rrreeeyyy
0
160
IBC 2024 動画技術関連レポート / IBC 2024 Report
cyberagentdevelopers
PRO
0
110
CysharpのOSS群から見るModern C#の現在地
neuecc
2
3.2k
The Rise of LLMOps
asei
7
1.4k
ISUCONに強くなるかもしれない日々の過ごしかた/Findy ISUCON 2024-11-14
fujiwara3
8
870
Lambda10周年!Lambdaは何をもたらしたか
smt7174
2
110
Featured
See All Featured
Code Review Best Practice
trishagee
64
17k
Into the Great Unknown - MozCon
thekraken
32
1.5k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Gamification - CAS2011
davidbonilla
80
5k
What's new in Ruby 2.0
geeforr
343
31k
Site-Speed That Sticks
csswizardry
0
23
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
16
2.1k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.1k
Making the Leap to Tech Lead
cromwellryan
133
8.9k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.3k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
27
840
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
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