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.