Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testing Flavors of Kotlin

Testing Flavors of Kotlin

A discovery over the different ways of testing in kotlin. Will go through Spek, HamKrest and Mockito. How to set it all up, how to do different kind of tests (intrumentation and unit).

0297b9b4bfd45c0f9c6c52bf696b7735?s=128

Bob Dahlberg

December 18, 2017
Tweet

Transcript

  1. 
 Testing flavors of Kotlin Bob Dahlberg - @mr_bob

  2. Bob Dahlberg Team Lead Mobile @ Isotop Who’s Bob?
 -

    Building software
 - Kotlin since 2015
 - Testing since Flash
  3. Somewhat painful testing

  4. Somewhat
 Painful
 Testing UI Testing - Use Espresso

  5. 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).”
  6. 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).”
  7. 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) } }
  8. 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) } }
  9. Unit Testing!

  10. Unit
 Testing The simplest unit class ExampleUnitTest { @Test fun

    addition_is_correct() { assertEquals(4, 2+2) } }
  11. 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) } }
  12. Unit
 Testing The simplest unit JUnit4 - assert class UnitTest

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

    { @Test fun startsWith() { val uri = "https://accepted.se" assertEquals(uri.substring(0,5), "https") } }
  14. 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) } }
  15. Unit
 Testing The simplest unit JUnit4 - assert
 Hamkrest class

    HamkrestUnitTest { @Test fun startsWith() { val uri = "https://accepted.se" assert.that(uri, startsWith(“https”)) } }
  16. 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”)) } }
  17. 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
  18. 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”) } }
  19. 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”) } }
  20. 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) } }
  21. Unit
 Testing The simplest unit JUnit4 - assert
 Hamkrest Mockito

    Mock everything @RunWith(MockitoJUnitRunner::class) class MockitoUnitTest { @Test fun inlineMocking() { val text = mock<TextView> { on { text } doReturn “text” on { elevation } doReturn 0.4f } val reverser = TextReverser(text) assert.that(reverser.text, equalTo("text".reversed())) } }
  22. Spek - from Specification

  23. Spek Another flavor Requires JUnit5
 Android standard is JUnit4
 Android

    Studio plugin (recommended)
 Writing specifications Given - When - Then
  24. 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) } } } })
  25. 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(“?")) } } })
  26. Spek Another flavor
 given - on - it describe -

    it
 Output
  27. Even more flavors

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

  29. More is More Expekt Kluent “Kotlin" shouldEqual “Kotlin" “Kotlin” shouldNotEqual

    “Scala" “Kotlin” `should not equal` "Scala" When calling stub.getPerson() itReturns bob
  30. More is More Expekt Kluent
 Rx2 Flowable.range(1, 5) .test() .assertResult(1,

    2, 3, 4, 5)
  31. 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)
  32. Thank you

  33. 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