Slide 1

Slide 1 text

Transforming Your Tests With Kotlin Victoria Gonda victoriagonda.com @TTGonda

Slide 2

Slide 2 text

Testing with Kotlin

Slide 3

Slide 3 text

https://twitter.com/TTGonda/status/1123025116139544576

Slide 4

Slide 4 text

Victoria Gonda • Android Engineer at Buffer • Author and Editor at RayWenderlich.com • Hedgehog and cat owner • she/her

Slide 5

Slide 5 text

Kotlin features

Slide 6

Slide 6 text

`Backticks`

Slide 7

Slide 7 text

https://twitter.com/skentphd/status/1123035724788453377 https://twitter.com/jshvarts/status/1123362376840040448

Slide 8

Slide 8 text

Without `Backticks` @Test fun whenDeleteIsCalled_onlyCorrespondingDataIsDeleted() { }

Slide 9

Slide 9 text

`Backticks` @Test fun `deleteUpdates only deletes corresponding data`() { }

Slide 10

Slide 10 text

`Backticks` java.lang.AssertionError: Assertion failed at package.Test.deleteUpdates only deletes corresponding data

Slide 11

Slide 11 text

Higher order functions

Slide 12

Slide 12 text

https://twitter.com/wakingrufus/status/ 1123053243800653825 https://twitter.com/RBusarow/status/ 1123057633261441024 https://twitter.com/jessewilson/status/ 1123055645824028672

Slide 13

Slide 13 text

Higher order functions fun verifyLinkOpen(expectedUrl: String, openLink: () -> Unit) { Intents.init() try { openLink() intended(allOf(hasAction(ACTION_VIEW), hasData(expectedUrl))) } finally { Intents.release() } }

Slide 14

Slide 14 text

Higher order functions verifyLinkOpen("https://buffer.com") { clickBufferButton() }

Slide 15

Slide 15 text

Screen Robots

Slide 16

Slide 16 text

Screen Robots class CalculatorScreenRobot : ScreenRobot() { fun verifyTipIsCorrect(tip: String): CalculatorScreenRobot { return checkViewHasText(R.id.textTip, tip) } fun inputCheckAmountAndSelectOkayButton(input: String): CalculatorScreenRobot { return enterTextIntoView(R.id.inputAmount, input) .clickOkOnView(R.id.buttonOkay) } }

Slide 17

Slide 17 text

Screen Robots withRobot(CalculatorScreenRobot::class.java) .inputCheckAmountAndSelectOkayButton("11") .verifyTipIsCorrect("1.98")

Slide 18

Slide 18 text

Screen Robots robot { inputCheckAmountAndSelectOkayButton("11") verifyTipIsCorrect("1.98") }

Slide 19

Slide 19 text

Extension functions

Slide 20

Slide 20 text

https://twitter.com/objcode/status/1123082385090908160

Slide 21

Slide 21 text

Without Extension functions assert(contentViewModel.observeQueueState().value == ContentState.Loading())

Slide 22

Slide 22 text

Extension functions private fun ContentViewModel.hasState(state: ContentState) { assert(observeQueueState().value == state) }

Slide 23

Slide 23 text

Extension functions contentViewModel.hasState(ContentState.Loading())

Slide 24

Slide 24 text

Infix functions

Slide 25

Slide 25 text

https://twitter.com/PreusslerBerlin/status/ 1123107023103696896 https://twitter.com/jossiwolf/status/ 1123039773541707776

Slide 26

Slide 26 text

Without Infix functions fun verifyTipIsCorrect(tip: String) { onView(withId(R.id.textTip)) .check(matches(withText(tip))) }

Slide 27

Slide 27 text

Infix functions infix fun Int.shouldHaveText(expected: String) { onView(withId(this)) .check(matches(withText(expected))) }

Slide 28

Slide 28 text

Infix functions fun verifyTipIsCorrect(tip: String) { R.id.textTip shouldHaveText tip }

Slide 29

Slide 29 text

Combining multiple features inline fun > robot(block: T.() -> Unit) { T::class.java.newInstance().block() } robot { inputCheckAmountAndSelectOkayButton("11") verifyTipIsCorrect("1.98") }

Slide 30

Slide 30 text

Data classes

Slide 31

Slide 31 text

https://twitter.com/shekibobo/status/ 1123037412328988673 https://twitter.com/tasomaniac/status/ 1123104225196683264

Slide 32

Slide 32 text

Data classes data class UpdateData( var shareMode: ShareMode = ShareMode.ADD_TO_QUEUE, var media: MediaEntity? = null, var extraMedia: Array? = null, var retweet: RetweetEntity? = null, @Nullable var scheduledAt: Long? = null, var text: String = "", var facebookText: String = "", var profileIds: List? = null, var subProfileIds: List? = null, var sourceUrl: String? = null, var importId: String? = null, var shareDetails: ShareDetails? = null, var userChangedMedia: Boolean = false, var isEditing: Boolean = false, var editingProfile: ProfileEntity? = null, var networks: List? = null, var facebookTags: List? = null, var id: String? = "", var lastEditedDate: Long? = 0, var editingProfileTimezone: String? = null, val location: Location? = null, val commentEnabled: Boolean = false, val commentText: String? = null )

Slide 33

Slide 33 text

Data classes UpdateData(null, null, emptyArray(), null, 0, "Hello World", "", emptyList(), emptyList(), null, "buffer.com", null, false, true, null, emptyList(), null, "", 0, null, null, false, "")

Slide 34

Slide 34 text

Data classes UpdateData(text = "Hello World", sourceUrl = "buffer.com")

Slide 35

Slide 35 text

Lazy property delegation

Slide 36

Slide 36 text

https://twitter.com/POTUS404/status/1123210124108103680

Slide 37

Slide 37 text

private val errorMessage by lazy { DataFactory.randomString() }

Slide 38

Slide 38 text

Example https://youtu.be/wlb3lg5JocA

Slide 39

Slide 39 text

Example https://youtu.be/wlb3lg5JocA

Slide 40

Slide 40 text

Kotlin libraries

Slide 41

Slide 41 text

Kakao

Slide 42

Slide 42 text

https://twitter.com/erafn/status/1123067587125026816

Slide 43

Slide 43 text

Kakao class SearchScreen : Screen() { val searchButton = KButton { withId(R.id.searchButton) } val snackbar = KView { withId(com.google.android.material.R.id.snackbar_text) } }

Slide 44

Slide 44 text

Kakao screen { searchButton.click() snackbar.isDisplayed() }

Slide 45

Slide 45 text

Spek

Slide 46

Slide 46 text

Spek class ProfileSpec : Spek({ given("twitter profile") { on("validate image count") { it("should be valid for four images") { } it("should fail for ten images") { } } } })

Slide 47

Slide 47 text

Spek Spek:ProfileSpec:given twitter profile:on validate image count:it 
 should be valid for four images
 => java.lang.AssertionError: Expected , actual .

Slide 48

Slide 48 text

Mockito-Kotlin

Slide 49

Slide 49 text

https://twitter.com/Exallium/status/1123214566052323329

Slide 50

Slide 50 text

Mockito val mockedUpdate = mock(Update::class.java) `when`(mockedUpdate.toString()).thenReturn("Update")

Slide 51

Slide 51 text

Mockito-Kotlin val mockedUpdate = mock { on { toString() } doReturn "Update" }

Slide 52

Slide 52 text

Kluent

Slide 53

Slide 53 text

Kluent message shouldEqual "hello" message.shouldEqual("hello") message `should equal` "hello"

Slide 54

Slide 54 text

Kluent invoking { read() } shouldThrow IOException::class

Slide 55

Slide 55 text

Kluent Verify on mockedUpdate that mockedUpdate.toString() was called When calling stub.length itReturns 4

Slide 56

Slide 56 text

Biscotti

Slide 57

Slide 57 text

Biscotti verifyActivityLaunched(MainActivity::class.java.name) { onView(withId(R.id.button_faq)) .perform(click()) }

Slide 58

Slide 58 text

https://vgonda.github.io/Talk-Resources/ @TTGonda

Slide 59

Slide 59 text

Thanks! Victoria Gonda victoriagonda.com @TTGonda