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

Writing Tests in Kotlin

Ivan
October 16, 2019

Writing Tests in Kotlin

Writing good tests is not easy, especially in Android. In this session, we will focus on writing tests in Kotlin. First, we will go through basic testing methods and how we implement them in Kotlin. Using Kotlin to write tests can also make your code more readable and maintainable. The second part of this session is going to cover some basics of a testing library, MockK. Finally, we will discuss the challenges and pitfalls of writing Kotlin tests on Android.

Kotlin Everywhere, Taiwan Kotlin User Group, Taipei

Ivan

October 16, 2019
Tweet

More Decks by Ivan

Other Decks in Programming

Transcript

  1. UTILIZE DATA CLASS 8 val expectedDesign = Design(id = 2,

    userId = 9, name = "Cat") assertThat(actualDesign).isEqualTo(expectedDesign) data class Design(val id: Int, val userId: Int, val name: String) org.junit.ComparisonFailure: expected:<Design (id=[2], userId=9, name=Cat...> but was:<Design(id=[1], userId=9, name=Cat…> Expected :Design(id=2, userId=9, name=Cat) Actual :Design(id=1, userId=9, name=Cat)
  2. SIMPLE TEST 9 class RepositoryTest { val userApi = initUserApi()

    @Test fun test1() {} @Test fun test2() {} } Created twice!
  3. IMPROVED TEST 10 class RepositoryTest { companion object { @JvmStatic

    private lateinit var userApi: UserApi @BeforeClass @JvmStatic fun init() { userApi = initUserApi() } } } It works.
  4. USE JUnit 5 11 @TestInstance(TestInstance.Lifecycle.PER_CLASS) class RepositoryTest { private val

    userApi = initUserApi() @Test fun test1() { } @Test fun test2() { } } YEAH!
  5. Why not just use Kotlin + Mockito? 12 Mockito is

    not compatible with some Kotlin features. Mockito?
  6. PITFALLS 13 Kotlin Class Mockito cannot mock Kotlin class ▸

    Open it! ▸ Force Mockito to mock it! Static Method You can use Mockito with PowerMock ▸ Version issues ▸ Compatibility Null! ERROR: “java.lang.IllegalStateExcep tion: anyObject() must not be null” Alternative Use mockito-kotlin
  7. MockK ▸ Completely for Kotlin ▸ Better expressions ▸ Easier

    to use ▸ Useful matchers, validators, and more. 15
  8. MockK FEATURES ▸ Spy ▸ Relaxed Mock ▸ Annotations ▸

    Object Mock ▸ Capturing ▸ Verification ▸ Extension Mock 16
  9. ANNOTATIO NS 17 @MockK lateinit var doc1: Dependency1 // Normal

    @SpyK val doc3 = Dependency3() @RelaxedMockK lateinit var doc2: Dependency2 @Before fun setup() { MockKAnnotations.init(this) } // Allows to mix mocks and real objs // Return simple values
  10. Spy 18 val car = spyk(Car()) // or spyk<Car>() to

    call default constructor car.drive(Direction.NORTH) // returns whatever real function of Car returns class Car { fun drive(direction: Int) = direction } every { car.drive(any()) } returns Direction.SOUTH car.drive(Direction.NORTH) // returns SOUTH
  11. Relaxed Mock 19 val car = mockk<Car>(relaxed = true) car.drive(Direction.NORTH)

    // returns null every { car.drive(any()) } returns Direction.SOUTH car.drive(Direction.NORTH) // returns SOUTH
  12. OBJECT MOCK 20 object MockObj { fun add(a: Int, b:

    Int) = a + b } mockkObject(MockObj) // applies mocking to an Object assertEquals(3, MockObj.add(1, 2)) every { MockObj.add(1, 2) } returns 55 assertEquals(55, MockObj.add(1, 2))
  13. CAPTURING 22 val slots = slot<ArrayList<String>>() verify { printer.print(capture(slots)) }

    printer.print("TheString1") printer.print("TheString2") printer.print("TheString3") assertEquals(slots[0], "TheString1") assertEquals(slots[1], "TheString2") assertEquals(slots[2], "TheString3")
  14. VERIFICATION atLeast atMost exactly 23 val car = mockk<Car>(relaxed =

    true) car.accelerate(fromSpeed = 10, toSpeed = 20) car.accelerate(fromSpeed = 10, toSpeed = 30) car.accelerate(fromSpeed = 20, toSpeed = 30) verify(atLeast = 3) { car.accelerate(allAny()) } verify(atMost = 2) { car.accelerate(fromSpeed = 10, toSpeed = or(20, 30)) } verify(exactly = 1) { car.accelerate(fromSpeed = 10, toSpeed = 20) } verify(exactly = 0) { car.accelerate(fromSpeed = 30, toSpeed = 10) }
  15. VERIFICATION ORDER 24 obj.sum(1, 2) obj.sum(1, 3) obj.sum(2, 2) verifyAll

    { obj.sum(1, 3) obj.sum(1, 2) obj.sum(2, 2) } verifySequence { obj.sum(1, 2) obj.sum(1, 3) obj.sum(2, 2) } verifyOrder { obj.sum(1, 2) obj.sum(2, 2) }
  16. Extension Functions 25 fun View.setVisible(visible: Boolean) { … } val

    viewExtensionPath = "com.example.ViewExtensionsKt" mockkStatic(viewExtensionPath) verify { view.setVisible(eq(false)) }
  17. ANDROID SUPPORT 26 ▸ Instrumentation test ▹ Not supported (<

    Android P) ▪ object mocks ▪ private function mocking ▪ extension function mocking (static mocks) ▪ constructor mocking https://mockk.io/ANDROID.html