Slide 1

Slide 1 text


 Testing flavors of Kotlin Bob Dahlberg - @mr_bob

Slide 2

Slide 2 text

Bob Dahlberg Team Lead Mobile @ Isotop Who’s Bob?
 - Building software
 - Kotlin since 2015
 - Testing since Flash

Slide 3

Slide 3 text

Somewhat painful testing

Slide 4

Slide 4 text

Somewhat
 Painful
 Testing UI Testing - Use Espresso

Slide 5

Slide 5 text

Somewhat
 Painful
 Testing UI Testing - Use Espresso Instrumentation Testing “You should create instrumented unit tests if your tests need access to instrumentation information (such as the target app’s context) or if they require the real implementation of an Android framework component (such as a Parcelable or SharedPreferences obj ect).”

Slide 6

Slide 6 text

Somewhat
 Painful
 Testing UI Testing - Use Espresso Instrumentation Testing “You should create instrumented unit tests if your tests need access to instrumentation information (such as the target app’s context) or if they require the real implementation of an Android framework component (such as a Parcelable or SharedPreferences obj ect).”

Slide 7

Slide 7 text

Somewhat
 Painful
 Testing UI Testing - Use Espresso Instrumentation Testing @RunWith(AndroidJUnit4::class) @SmallTest class InstrumentedExampleTest { @Test fun use_app_context() { val appContext = InstrumentationRegistry.getTargetContext() assertEquals(“se.accepted.test”, appContext.packageName) } }

Slide 8

Slide 8 text

Somewhat
 Painful
 Testing UI Testing - Use Espresso Instrumentation Testing - Databases - Real Permissions - Build version specific on device - Black box testing - Learning @RunWith(AndroidJUnit4::class) @SmallTest class InstrumentedExampleTest { @Test fun use_app_context() { val appContext = InstrumentationRegistry.getTargetContext() assertEquals(“se.accepted.test”, appContext.packageName) } }

Slide 9

Slide 9 text

Unit Testing!

Slide 10

Slide 10 text

Unit
 Testing The simplest unit class ExampleUnitTest { @Test fun addition_is_correct() { assertEquals(4, 2+2) } }

Slide 11

Slide 11 text

Unit
 Testing The simplest unit class ExampleUnitTest { @Test fun addition_is_correct() { assertEquals(4, 2+2) } @Test fun addition_on_person() { val bob = Person(age=33) val oldBob = bob+1 assertEquals(34, oldBob.age) } }

Slide 12

Slide 12 text

Unit
 Testing The simplest unit JUnit4 - assert class UnitTest { @Test fun startsWith() { val uri = "https://accepted.se" assertEquals(uri.substring(0,4), "http") } }

Slide 13

Slide 13 text

Unit
 Testing The simplest unit JUnit4 - assert class UnitTest { @Test fun startsWith() { val uri = "https://accepted.se" assertEquals(uri.substring(0,5), "https") } }

Slide 14

Slide 14 text

Unit
 Testing The simplest unit JUnit4 - assert class UnitTest { @Test fun startsWith() { val uri = "https://accepted.se" assertEquals(uri.substring(0,5), "https") assertEquals(uri.indexOf("https"), 0) } }

Slide 15

Slide 15 text

Unit
 Testing The simplest unit JUnit4 - assert
 Hamkrest class HamkrestUnitTest { @Test fun startsWith() { val uri = "https://accepted.se" assert.that(uri, startsWith(“https”)) } }

Slide 16

Slide 16 text

Unit
 Testing The simplest unit JUnit4 - assert
 Hamkrest class HamkrestUnitTest { @Test fun startsWith() { val uri = "https://accepted.se" assert.that(uri, startsWith(“https") and endsWith(“.se”)) } }

Slide 17

Slide 17 text

Unit
 Testing The simplest unit JUnit4 - assert
 Hamkrest class HamkrestUnitTest { @Test fun startsWith() { val hasOnlyOneColon = Matcher(String::singleChar,’:’) val uri = "https://accepted.se" assert.that(uri, startsWith(“https") and hasOnlyOneColon) } } fun String.singleChar(c:Char):Boolean = count{ it == c } == 1

Slide 18

Slide 18 text

Unit
 Testing The simplest unit JUnit4 - assert
 Hamkrest Mockito @RunWith(MockitoJUnitRunner::class) class MockitoUnitTest { @Mock private lateinit var header:IText @Test fun presenterSetsHeader() { val response = ApiResponse(title=“my header”) val presenter = Presenter() presenter.attachView(header) presenter.onData(response) verify(header).setText(“my header”) } }

Slide 19

Slide 19 text

Unit
 Testing The simplest unit JUnit4 - assert
 Hamkrest Mockito class MockitoUnitTest { @Mock private lateinit var header:IText @Before fun setUp() { MockitoAnnotations.initMocks(this) } @Test fun presenterSetsHeader() { val response = ApiResponse(title=“my header”) val presenter = Presenter() presenter.attachView(header) presenter.onData(response) verify(header).setText(“my header”) } }

Slide 20

Slide 20 text

Unit
 Testing The simplest unit JUnit4 - assert
 Hamkrest Mockito Mock everything @RunWith(MockitoJUnitRunner::class) class MockitoUnitTest { @Mock private lateinit var context:Context val myText = "Any requested string" @Before fun setUp() { whenever(context.getString(any())).thenReturn(myText) } @Test fun presenterSetsHeader() { val fromResource = context.getString(R.string.my_string) assertEquals(myText, fromResource) } }

Slide 21

Slide 21 text

Unit
 Testing The simplest unit JUnit4 - assert
 Hamkrest Mockito Mock everything @RunWith(MockitoJUnitRunner::class) class MockitoUnitTest { @Test fun inlineMocking() { val text = mock { on { text } doReturn “text” on { elevation } doReturn 0.4f } val reverser = TextReverser(text) assert.that(reverser.text, equalTo("text".reversed())) } }

Slide 22

Slide 22 text

Spek - from Specification

Slide 23

Slide 23 text

Spek Another flavor Requires JUnit5
 Android standard is JUnit4
 Android Studio plugin (recommended)
 Writing specifications Given - When - Then

Slide 24

Slide 24 text

Spek Another flavor
 given - on - it class ExampleSpek : Spek({ given(“a father”) { val bob = Person(“Bob”,33) on(“Sunday morning”){ bob.time = SundayMorning() it(“should be awake”){ assertThat(bob.awake, true) } it(“should play with his child”){ assertThat(bob.isPlaying, true) } it(“should be tired”){ assertThat(bob.tired, true) } } } })

Slide 25

Slide 25 text

Spek Another flavor
 given - on - it describe - it class ExampleSpek : Spek({ describe(“a stream from a channel”) { val stream = Channel("http://stream.dash").asStream() it(“is not null”){ assertThat(stream, anything) } it(“has an uri”){ assertThat(stream.uri, !isEmptyString) } it(“has a query”){ assertThat(stream.uri, containsSubstring(“?")) } } })

Slide 26

Slide 26 text

Spek Another flavor
 given - on - it describe - it
 Output

Slide 27

Slide 27 text

Even more flavors

Slide 28

Slide 28 text

More is More Expekt 23.should.equal(23) “Kotlin".should.not.contain("Scala") listOf(1, 2, 3).should.have.size.above(1)

Slide 29

Slide 29 text

More is More Expekt Kluent “Kotlin" shouldEqual “Kotlin" “Kotlin” shouldNotEqual “Scala" “Kotlin” `should not equal` "Scala" When calling stub.getPerson() itReturns bob

Slide 30

Slide 30 text

More is More Expekt Kluent
 Rx2 Flowable.range(1, 5) .test() .assertResult(1, 2, 3, 4, 5)

Slide 31

Slide 31 text

More is More Expekt Kluent
 Rx2 Flowable.range(1, 5) .test(0) .assertValues() .requestMore(1) .assertValues(1) .requestMore(2) .assertValues(1, 2, 3) .requestMore(2) .assertResult(1, 2, 3, 4, 5)

Slide 32

Slide 32 text

Thank you

Slide 33

Slide 33 text

Bob Dahlberg @mr_bob - twitter @dahlberg.bob - medium.com bobdahlberg - speakerdeck.com com.nhaarman:mockito-kotlin-kt1.1:1.5.0 com.natpryce:hamkrest:1.4.2.2 org.jetbrains.spek:spek-api:1.1.5 org.amshove.kluent:kluent-android:1.32 com.winterbe:expekt:0.5.0 speakerdeck.com/bobdahlberg/testing-flavors-of-kotlin