Unit Testing in Kotlin Egor Andreevici Software Developer @ 1&1 @EgorAnd
Android: In The Java Zone
Java Kotlin + Official + Stable - Old - Verbose + Modern + Expressive - Stable? - Support?
Starting with Kotlin on Android? Start small! Start with unit tests!
Unit Tests Are Good
Benefits of Unit Tests Provide a safety net around your code Document your code… what? Promote good design practices
Bad Documentation /** * Get a subview of the root view at a certain position. * * @param position Position, 0 <= position < root child count * @return Subview at given position, or {@code null} if position is out of * bounds */ public View getViewAtPosition(int position) { if (position >= 0 && position < root.getChildCount()) { return root.getChildAt(position); } return null; }
Bad Documentation /** * Get a subview of the root view at a certain position. * * @param position Position, 0 <= position < root child count * @return Subview at given position, or {@code null} if position is out of * bounds */ public View getViewAtPosition(int position) { if (position >= 0 && position < root.getChildCount()) { return root.getChildAt(position); } throw new IndexOutOfBoundsException("Invalid position " + position); }
A Better Test @Test public void shouldReturnNullIfCalledWithInvalidPosition() { doReturn(0).when(mockParent).getChildCount(); assertThat(docs.getViewAtPosition(0)).isNull(); }
EvenBetterTest.kt
Kotlinize @Test fun shouldReturnNullIfCalledWithInvalidPosition() { doReturn(0).`when`<ViewGroup>(mockParent).childCount assertThat(docs.getViewAtPosition(0)).isNull() }
Better Method Names @Test fun `Should return null if called with invalid position`() { doReturn(0).`when`<ViewGroup>(mockParent).childCount assertThat(docs.getViewAtPosition(0)).isNull() }
Better Mocking with Mockito-Kotlin ● Reified types for mock creation ● Fluent method mocking syntax ● More niceties
Better Mocking with Mockito-Kotlin private var mockParent = mock<ViewGroup>()
Better Mocking with Mockito-Kotlin // private var mockParent = mock<ViewGroup>() private var mockParent: ViewGroup = mock { on { childCount } doReturn 0 }
Better Mocking with Mockito-Kotlin @Test fun `Should return null if called with invalid position`() { whenever(mockParent.childCount) doReturn 0 assertThat(docs.getViewAtPosition(0)).isNull() }
How Does It Work? inline fun <reified T : Any> mock(): T = Mockito.mock(T::class.java)
Better Assertions with Kluent @Test fun `Should return null if called with invalid position`() { whenever(mockParent.childCount) doReturn 0 docs.getViewAtPosition(0) `should be` null }
How Does It Work? import org.junit.Assert.* infix fun Any?.`should be`(theOther: Any?) = assertSame(theOther, this) infix fun Any?.shouldBe(theOther: Any?) = this `should be` theOther
Other Goodies
Multiline Strings val json = """ { "name": "Bob", "age": 57 } """ @Test fun `Should parse JSON correctly`() { gson.fromJson(json, Person::class.java) `should equal` Person("Bob", 57) }
“with” for Multiple Assertions @Test fun `Should parse JSON correctly #2`() { val person = gson.fromJson(json, Person::class.java) with(person) { name `should equal` "Bob" age `should equal` 57 } }
Factory Functions with Named Args public class Person { private String name; private int age; private boolean isAKotlinProgrammer; public Person(String name, int age, boolean isAKotlinProgrammer) { this.name = name; this.age = age; this.isAKotlinProgrammer = isAKotlinProgrammer; } … }
Factory Functions with Named Args fun person( name: String = "", age: Int = 0, isAKotlinProgrammer: Boolean = false) = Person(name, age, isAKotlinProgrammer) @Test fun `Should ...`() { val person = person(name = "Bob", age = 57) ... }
@JvmOverloads @JvmOverloads fun person( name: String = "", age: Int = 0, isAKotlinProgrammer: Boolean = false) = Person(name, age, isAKotlinProgrammer)
...and more magic in store!
Thanks! Egor Andreevici Software Developer @ 1&1 @EgorAnd

Unit Testing in Kotlin

  • 1.
    Unit Testing inKotlin Egor Andreevici Software Developer @ 1&1 @EgorAnd
  • 2.
    Android: In TheJava Zone
  • 3.
    Java Kotlin + Official +Stable - Old - Verbose + Modern + Expressive - Stable? - Support?
  • 4.
    Starting with Kotlinon Android? Start small! Start with unit tests!
  • 5.
  • 6.
    Benefits of UnitTests Provide a safety net around your code Document your code… what? Promote good design practices
  • 7.
    Bad Documentation /** * Geta subview of the root view at a certain position. * * @param position Position, 0 <= position < root child count * @return Subview at given position, or {@code null} if position is out of * bounds */ public View getViewAtPosition(int position) { if (position >= 0 && position < root.getChildCount()) { return root.getChildAt(position); } return null; }
  • 8.
    Bad Documentation /** * Geta subview of the root view at a certain position. * * @param position Position, 0 <= position < root child count * @return Subview at given position, or {@code null} if position is out of * bounds */ public View getViewAtPosition(int position) { if (position >= 0 && position < root.getChildCount()) { return root.getChildAt(position); } throw new IndexOutOfBoundsException("Invalid position " + position); }
  • 9.
    A Better Test @Testpublic void shouldReturnNullIfCalledWithInvalidPosition() { doReturn(0).when(mockParent).getChildCount(); assertThat(docs.getViewAtPosition(0)).isNull(); }
  • 10.
  • 11.
    Kotlinize @Test fun shouldReturnNullIfCalledWithInvalidPosition(){ doReturn(0).`when`<ViewGroup>(mockParent).childCount assertThat(docs.getViewAtPosition(0)).isNull() }
  • 12.
    Better Method Names @Testfun `Should return null if called with invalid position`() { doReturn(0).`when`<ViewGroup>(mockParent).childCount assertThat(docs.getViewAtPosition(0)).isNull() }
  • 13.
    Better Mocking withMockito-Kotlin ● Reified types for mock creation ● Fluent method mocking syntax ● More niceties
  • 14.
    Better Mocking withMockito-Kotlin private var mockParent = mock<ViewGroup>()
  • 15.
    Better Mocking withMockito-Kotlin // private var mockParent = mock<ViewGroup>() private var mockParent: ViewGroup = mock { on { childCount } doReturn 0 }
  • 16.
    Better Mocking withMockito-Kotlin @Test fun `Should return null if called with invalid position`() { whenever(mockParent.childCount) doReturn 0 assertThat(docs.getViewAtPosition(0)).isNull() }
  • 17.
    How Does ItWork? inline fun <reified T : Any> mock(): T = Mockito.mock(T::class.java)
  • 18.
    Better Assertions withKluent @Test fun `Should return null if called with invalid position`() { whenever(mockParent.childCount) doReturn 0 docs.getViewAtPosition(0) `should be` null }
  • 19.
    How Does ItWork? import org.junit.Assert.* infix fun Any?.`should be`(theOther: Any?) = assertSame(theOther, this) infix fun Any?.shouldBe(theOther: Any?) = this `should be` theOther
  • 20.
  • 21.
    Multiline Strings val json= """ { "name": "Bob", "age": 57 } """ @Test fun `Should parse JSON correctly`() { gson.fromJson(json, Person::class.java) `should equal` Person("Bob", 57) }
  • 22.
    “with” for MultipleAssertions @Test fun `Should parse JSON correctly #2`() { val person = gson.fromJson(json, Person::class.java) with(person) { name `should equal` "Bob" age `should equal` 57 } }
  • 23.
    Factory Functions withNamed Args public class Person { private String name; private int age; private boolean isAKotlinProgrammer; public Person(String name, int age, boolean isAKotlinProgrammer) { this.name = name; this.age = age; this.isAKotlinProgrammer = isAKotlinProgrammer; } … }
  • 24.
    Factory Functions withNamed Args fun person( name: String = "", age: Int = 0, isAKotlinProgrammer: Boolean = false) = Person(name, age, isAKotlinProgrammer) @Test fun `Should ...`() { val person = person(name = "Bob", age = 57) ... }
  • 25.
    @JvmOverloads @JvmOverloads fun person( name: String= "", age: Int = 0, isAKotlinProgrammer: Boolean = false) = Person(name, age, isAKotlinProgrammer)
  • 26.
  • 27.