61
Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Best Practices for Unit Testing in Kotlin @philipp_hauerSpreadshirt

KotlinConf, AmsterdamOct 05, 2018

Page 2: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Question

Page 3: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

My First Test in Kotlin...

Page 4: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

4

open class UserRepositoryclass UserControllerTest { companion object { @JvmStatic lateinit var controller: UserController @JvmStatic lateinit var repo: UserRepository @BeforeClass @JvmStatic initialize() { repo = mock() controller = UserController(repo) } } @Test fun findUser_UserFoundAndHasCorrectValues() { `when`(repo.findUser(1)).thenReturn(User(1, "Peter")) val user = controller.getUser(1) assertEquals(user?.name, "Peter") }}

mu l ! re g a l !bu , s a c!

op qu

Har R ad!

Po r E r Me g

Bet Moc AP ?

Bo l la !

Page 5: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

5

We can do better!

Re d e

Cle

Idi ic

Con

Re s a l F i Mes s

Page 6: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

6

How?

Tes c le

Tes r i

Nam , Gro g

Moc d g

The of Dat se

Sp i g I eg on

Page 7: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Recap: Idiomatic Kotlin Code

Page 8: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Idiomatic Kotlin Code

8

Immutability Non-Nullability

No Static Access

valvar

StringString?

No direct language feature

Page 9: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Test Class Lifecycle

Page 10: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

class RepositoryTest {

}

JUnit4: Always New Test Class Instances

10

@Test fun test1() { ... }

@Test fun test2() { ... }

instance1: RepositoryTest

instance2: RepositoryTest

Where to put the initial setup code?

val mongo = startMongoContainer()Exe d o e c te

Page 11: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

JUnit4: Static for the Initial Setup Code

11

class RepositoryTest { companion object { @JvmStatic private lateinit var mongo: GenericContainer @JvmStatic private lateinit var repo: Repository @BeforeClass @JvmStatic fun initialize() { mongo = startMongoContainer() repo = Repository(mongo.host, mongo.port) } }}

mu ls a c

Bo l la ! nuwo r u

Page 12: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

JUnit5 to the Rescue!

12

Page 13: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

JUnit5: Reuse the Test Class Instance

13

@TestInstance(TestInstance.Lifecycle.PER_CLASS)class RepositoryTest {

}

private val mongo = startMongoContainer().apply { configure() } private val repo = Repository(mongo.host, mongo.port)

@Test fun test1() { }

ConIdi ic

Page 14: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

JUnit5: Reuse the Test Class Instance

14

@TestInstance(TestInstance.Lifecycle.PER_CLASS)class RepositoryTest { private val mongo: GenericContainer private val repo: Repository init { mongo = startMongoContainer().apply { configure() } repo = Repository(mongo.host, mongo.port) }}

Page 15: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

JUnit5: Change the Lifecycle Default

15

junit.jupiter.testinstance.lifecycle.default = per_class

src/test/resources/junit-platform.properties:

@TestInstance(TestInstance.Lifecycle.PER_CLASS)

Page 16: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Test Names and Grouping

Page 17: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Backticks

17

class TagClientTest { @Test fun `basic tag list`() {} @Test fun `empty tag list`() {}}

Page 18: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

18

Whi t b o g to c t o ?

Page 19: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

@Nested Inner Classes

19

class DesignControllerTest { @Nested inner class GetDesigns { @Test fun `all fields are included`() {} @Test fun `limit parameter`() {} } @Nested inner class DeleteDesign { @Test fun `design is removed in db`() {} }}

getDesign()

deleteDesign()

Page 20: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

20

Page 21: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Kotlin Test Libraries

Page 22: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Being Spoilt for Choice

22

Incomplete list.Some libraries fit into multiple categories.

Test Frameworks Mocking Assertions

Kotlin

Java

SpekKotlinTest

JUnit5

Mockito-KotlinMockK

Strikt AtriumHamKrest Expekt

Kluent AssertK

AssertJ

My e s c o (fo w)

Page 23: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Test-Specific Extension Functions

23

assertThat(taxRate1).isCloseTo(0.3f, Offset.offset(0.001f))assertThat(taxRate2).isCloseTo(0.2f, Offset.offset(0.001f))assertThat(taxRate3).isCloseTo(0.5f, Offset.offset(0.001f))

fun AbstractFloatAssert<*>.isCloseTo(expected: Float) = this.isCloseTo(expected, Offset.offset(0.001f))

// Usage:assertThat(taxRate1).isCloseTo(0.3f)assertThat(taxRate2).isCloseTo(0.2f)assertThat(taxRate3).isCloseTo(0.5f)

Dup ti

CleIdi ic

Page 24: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Mock Handling

Page 25: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Classes Are Final by Default

25

Solutions

● Interfaces● open explicitly● Mockito: Enable incubating feature to

mock final classes● MockK

Page 26: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

MockK

26

val clientMock: UserClient = mockk()every { clientMock.getUser(any()) }

returns User(id = 1, name = "Ben")

val updater = UserUpdater(clientMock)updater.updateUser(1)

verify { clientMock.getUser(1) }

mockk(relaxed=true)

Page 27: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

MockK

27

java.lang.AssertionError: Verification failed: calls are not exactly matching verification sequence

Matchers: UserClient(#5).getUser(eq(2)))UserRepo(#4).saveUser(eq(User(id=1, name=Ben, age=29))))

Calls:1) UserClient(#5).getUser(1)2) UserRepo(#4).saveUser(User(id=1, name=Ben, age=29))

verifySequence { clientMock.getUser(2) repoMock.saveUser(user)}

Page 28: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Does Test Speed Matter?

28

2 s o 31 Uni T t ?

Page 29: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Don't Recreate Mocks

29

class DesignControllerTest { private lateinit var repo: DesignRepository private lateinit var client: DesignClient private lateinit var controller: DesignController @BeforeEach fun init() { repo = mockk() client = mockk() controller = DesignController(repo, client) }}

Ex e s !

Page 30: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Create Mocks Once, Reset Them

30

class DesignControllerTest { private val repo: DesignRepository = mockk() private val client: DesignClient = mockk() private val controller = DesignController(repo, client) @BeforeEach fun init() { clearMocks(repo, client) }}

Fas

Page 31: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Create Mocks Once, Reset Them

31

2.1 s

0.4 s

Page 32: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Handle Classes with State

32

class DesignViewTest { private val repo: DesignRepository = mockk() private lateinit var view: DesignView @BeforeEach fun init() { clearMocks(repo) view = DesignView(repo) } @Test fun changeButton() { assertThat(view.button.caption).isEqualTo("Hi") view.changeButton() assertThat(view.button.caption).isEqualTo("Guten Tag") }}

s a f

re-c e on ir

Page 33: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Spring Integration

Page 34: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

All-Open Compiler Plugin

34

@Configurationclass SpringConfiguration{ @Bean fun objectMapper() = ObjectMapper().registerKotlinModule()}

BeanDefinitionParsingException: Configuration problem: @Configuration class 'SpringConfiguration' may not be final.

<dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-allopen</artifactId> <version>${kotlin.version}</version></dependency>

<compilerPlugins> <plugin>spring</plugin></compilerPlugins>

Page 35: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Constructor Injection for Spring-free Testing

35

@Componentclass DesignController( private val designRepo: DesignRepository, private val designClient: DesignClient,) {}

Eas t Log t o Sp g:

val repo: DesignRepository = mockk()val client: DesignClient = mockk()val controller = DesignController(repo, client)

Page 36: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Utilize Data Classes

Page 37: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

org.junit.ComparisonFailure: expected:<[2]> but was:<[1]>Expected :2Actual :1

Data Classes for Assertions

37

assertThat(actualDesign.id).isEqualTo(2) assertThat(actualDesign.userId).isEqualTo(9)assertThat(actualDesign.name).isEqualTo("Cat")

???

Page 38: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Data Classes for Assertions

38

val expectedDesign = Design(id = 2, userId = 9, name = "Cat")assertThat(actualDesign).isEqualTo(expectedDesign)

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)

se -ex n o y

Page 39: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Expecting: <[Design(id=1, userId=9, name=Cat), Design(id=2, userId=4, name=Dogggg)]>to contain exactly (and in same order): <[Design(id=1, userId=9, name=Cat), Design(id=2, userId=4, name=Dog)]>but some elements were not found: <[Design(id=2, userId=4, name=Dog)]>and others were not expected: <[Design(id=2, userId=4, name=Dogggg)]>

Data Classes for Assertions

39

assertThat(actualDesigns).containsExactly( Design(id = 1, userId = 9, name = "Cat"), Design(id = 2, userId = 4, name = "Dog"))

Gre !

Page 40: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Data Classes for Assertions

40

assertThat(actualDesign).isEqualToIgnoringGivenFields(expectedDesign,"id")

assertThat(actualDesigns).usingElementComparatorIgnoringFields("id").containsExactly(expectedDesign1, expectedDesign2)

assertThat(actualDesigns).usingElementComparatorOnFields("name").containsExactly(expectedDesign1, expectedDesign2)

assertThat(actualDesign).isEqualToComparingOnlyGivenFields(expectedDesign,"name")

Lists

Single Element

Page 41: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Helper Function for Object Creation

41

val testDesign = Design(id = 1,userId = 9name = "Fox",dateCreated = Instant.now(),tags = mapOf()

)val testDesign2 = Design(

id = 2,userId = 9name = "Cat",dateCreated = Instant.now(),tags = mapOf()

)

- Blo c e- Are p s e v

fo h t?

Page 42: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Helper Function for Object Creation

42

fun createDesign( id: Int = 1, name: String = "Cat", date: Instant = Instant.ofEpochSecond(1518278198), tags: Map<Locale, List<Tag>> = mapOf( Locale.US to listOf(Tag(value = "$name in English")), )) = Design( id = id, userId = 9, name = name, dateCreated = date, tags = tags)

// Usage:val testDesign = createDesign()val testDesign2 = createDesign(

id = 1,name = "Fox"

) Con

Page 43: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Helper Function for Object Creation

43

repo.saveAll( createDesign(isEnabled = true, language = Locale.US), createDesign(isEnabled = true, language = Locale.GERMANY), createDesign(isEnabled = false, language = Locale("nl","NL")))

Ta l e Cr i F n i n fo C r Tes

CurrentTest.kt:

Page 44: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Helper Function for Object Creation

44

fun createDesign( isEnabled: Boolean, language: Locale) = createDesign( description = createDescription(

translations = createTranslationsFor(language) ), state = if (isEnabled) createDisabledState() else createEnabledState())

CreationUtils.kt

CurrentTest.kt:

Page 45: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Data Classes for Parameterized Tests

45

@Testfun `parse valid tokens`() { assertThat(parse("1511443755_2")).isEqualTo(Token(1511443755, "2")) assertThat(parse("151175_13521")).isEqualTo(Token(151175, "13521")) assertThat(parse("151144375_id")).isEqualTo(Token(151144375, "id")) assertThat(parse("1511443759_1")).isEqualTo(Token(1511443759, "1")) assertThat(parse(null)).isEqualTo(null)}

Whi n a d?

Page 46: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Data Classes for Parameterized Tests

46

data class TestData( val input: String?, val expected: Token?)

Page 47: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Data Classes for Parameterized Tests

47

@ParameterizedTest@MethodSource("validTokenProvider")fun `parse valid tokens`(testData: TestData) { assertThat(parse(testData.value)).isEqualTo(testData.expectedToken)}private fun validTokenProvider() = Stream.of( TestData(input = "1511443755_2", expected = Token(1511443755, "2")), TestData(input = "151175_13521", expected = Token(151175, "13521")), TestData(input = "151144375_id", expected = Token(151144375, "id")), TestData(input = "1511443759_1", expected = Token(1511443759, "1")), TestData(input = null, expected = null))

Page 48: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Conclusion

Page 49: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

49

open class UserRepositoryclass UserControllerTest { companion object { @JvmStatic lateinit var controller: UserController @JvmStatic lateinit var repo: UserRepository @BeforeClass @JvmStatic initialize() { repo = mock() controller = UserController(repo) } } @Test fun findUser_UserFoundAndHasCorrectValues() { `when`(repo.findUser(1)).thenReturn(User(1, "Peter")) val user = controller.getUser(1) assertEquals(user?.name, "Peter") }}

Page 50: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

50

class UserControllerTest { private val repo: UserRepository = mockk() private val controller = UserController(repo) @Test fun `find user with correct values`() { every { repo.findUser(1) } returns User(1, "Peter") val user = controller.getUser(1) assertEquals(user).isEqualTo(User(1, "Peter")) }}

Page 51: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018
Page 52: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

52

Data Classes FTW

Best Practices for Testing in Kotlin

Equ As e tCre o H l

@Par er Tes

Naming, GroupingBac c @Nes

Mock HandlingDon't e r e; re !

Moc

JUnit5 Kotlin @Tes I s a c (PE _C A S)

LibrariesCho o r ge

Page 53: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

53https://blog.philipphauer.de/best-practices-unit-testing-kotlin/

Page 54: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Thank you!

@philipp_hauerSpreadshirt

KotlinConf, AmsterdamOct 05, 2018

Page 55: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Backup Slides

Page 56: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Test-Specific Extension Functions

56

mvc.perform(get("designs/123?platform=$invalidPlatform")) .andExpect(status().isBadRequest) .andExpect(jsonPath("errorCode").value(code)) .andExpect(jsonPath("details", startsWith(msg)))

fun ResultActions.andExpectErrorPage(code: Int, msg: String) = this.andExpect(status().isBadRequest) .andExpect(jsonPath("errorCode").value(code)) .andExpect(jsonPath("details", startsWith(msg)))

// Usage:mvc.perform(get("designs/123?platform=$invalidPlatform")) .andExpectErrorPage(130, "Invalid platform.")

Page 57: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Spring Integration

Page 58: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Mock-based Spring Test Context

58

@ExtendWith(SpringExtension::class)@WebMvcTest(DesignController::class)@Import(TestConfig::class)class DesignControllerTest { @Autowired private lateinit var mvc: MockMvc @Autowired private lateinit var repoMock: DesignRepository @BeforeEach fun init() { clearMocks(repoMock) } @Test fun test() {}}

@Configurationprivate class TestConfig { @Bean fun repoMock(): DesignRepository

= mockk()}

Page 59: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Spring Test Context for an Integration Test

59

@Configurationprivate class TestConfig { @Bean fun repo() = repo private val repo: DesignRepository init { val mongo = startMongoContainer() val mongoTemplate = createMongoTemplate(mongo.host, mongo.port) repo = DesignRepository(mongoTemplate) }}

Ini se va le Sp g

Page 60: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

About Spreadshirt

Page 61: Oct 05, 2018 Best Practices KotlinConf, Amsterdam for Unit ...€¦ · Best Practices for Unit Testing in Kotlin @philipp_hauer Spreadshirt KotlinConf, Amsterdam Oct 05, 2018

Spreadshirt

61

For two years