Testing with Kotlin
-
Upload
robert-fletcher -
Category
Software
-
view
4.868 -
download
0
Transcript of Testing with Kotlin
TESTING WITH KOTLINRob Fletcher — @rfletcherEW
Senior Enterprise Bean Deployer, Netflix
ITERATIVE TESTSone test, many data points
ITERATION – SPOCK
def "the diamond function rejects illegal characters"() { when: diamond.of(c) then: thrown IllegalArgumentException where: c << generator.chars() .findAll { !('A'..'Z').contains(it) } .take(100) }
ITERATION – SPEK
describe("handling invalid characters") {
chars().filter { it !in 'A'..'Z' } .take(100) .forEach { c -> it("throws an exception") assertFailsWith(IllegalArgumentException::class) { diamond.of(c) } } } }
TOKENIZED TEST NAMES – SPOCK
@Unroll def "the diamond function rejects #c"() { when: diamond.of(c)
then: thrown IllegalArgumentException
where: c << generator.chars() .findAll { !('A'..'Z').contains(it) } .take(100) }
TOKENIZED TEST NAMES – SPEK
describe("handling invalid characters") { chars().filter { it !in 'A'..'Z' } .take(100) .forEach { c -> it("throws an exception for '$c'") assertFailsWith(IllegalArgumentException::class) { diamond.of(c) } } } }
NESTED ITERATION – SPEK
('B'..'Z').forEach { c -> describe("the diamond of '$c'") { val result = diamond.of(c)
it("is square") { assert(result.all { it.length == rows.size }) } ('A'..c).forEach { rowChar -> val row = rowChar - 'A' val col = c - rowChar it("has a '$rowChar' at row $row column $col") { assertEquals(rowChar, result[row][col]) } } } }
TABULAR ITERATION – SPOCK
@Unroll def "the diamond of #c has #height rows"() { expect: diamond.of(c).size == height
where: c | height 'A' | 1 'B' | 3 'C' | 5 }
TABULAR ITERATION – SPEK
for ((c, height) in mapOf('A' to 1, 'B' to 2, 'C' to 3)) { describe("the diamond of '$c") { val result = diamond(c) it("has $height rows") { assertEquals(height, result.size) } } }
MOCKSMockito meets Kotlin
MOCKITO – SPEK
describe("publishing events") { val eventBus = EventBus() val subscriber = mock(Subscriber::class.java) as Subscriber<ExampleEvent> beforeEach { eventBus.post(ExampleEvent("test running")) } it("should send the event to the subscriber") { verify(subscriber) .onEvent(argThat { (it as ExampleEvent).description == "test running" }) } }
MOCKITO – SPEK
describe("publishing events") { val eventBus = EventBus() val subscriber = mock(Subscriber::class.java) as Subscriber<ExampleEvent> beforeEach { eventBus.post(ExampleEvent("test running")) } it("should send the event to the subscriber") { verify(subscriber) .onEvent(argThat { (it as ExampleEvent).description == "test running" }) } }
Can't infer generic type
Can't infer generic matcher argument
MOCKITO – SPEK
describe("publishing events") { val eventBus = EventBus() val subscriber = mock(Subscriber::class.java) as Subscriber<ExampleEvent> beforeEach { eventBus.post(ExampleEvent("test running")) } it("should send the event to the subscriber") { verify(subscriber) .onEvent(argThat { (it as ExampleEvent).description == "test running" }) } }
Returns null so fails at runtime
MOCKITO – SPEK
repositories { jcenter() } dependencies { compile "com.nhaarman:mockito-kotlin:0.4.1" }
MOCKITO – SPEK
describe("publishing events") { val eventBus = EventBus() val subscriber: Subscriber<Event> = mock() beforeEach { eventBus.post(Event("test running")) } it("should send the event to the subscriber") { verify(subscriber).onEvent(argThat { description == "test running" }) } }
MOCKITO – SPEK
describe("publishing events") { val eventBus = EventBus() val subscriber: Subscriber<Event> = mock() beforeEach { eventBus.post(Event("test running")) } it("should send the event to the subscriber") { verify(subscriber).onEvent(argThat { description == "test running" }) } }
Type inference on receiver
Reified generics allow type inference
MOCKITO – SPEK
describe("publishing events") { val eventBus = EventBus() val subscriber: Subscriber<Event> = mock() beforeEach { eventBus.post(Event("test running")) } it("should send the event to the subscriber") { verify(subscriber).onEvent(argThat { description == "test running" }) } }
Returns dummy value
TCKSmultiple implementations, one set of tests
TCK – SPOCK
abstract class PubSubSpec extends Specification { @Subject abstract EventBus factory() // ... tests appear here} class SyncPubSubSpec extends PubSubSpec { @Override EventBus factory() { new EventBus() } } class AsyncPubSubSpec extends PubSubSpec { @Override EventBus factory() { new AsyncEventBus(newSingleThreadExecutor()) } }
TCK – SPEK
abstract class PubSubTck(val eventBus: EventBus) : Spek ( { describe("publishing events") { // ... tests appear here } } ) class SyncPubSubSpec : PubSubTck(EventBus()) class AsyncPubSubSpec : PubSubTck(AsyncEventBus(newSingleThreadExecutor()))
TCK WITH FACTORY – SPEK
abstract class PubSubTck(val factory: () -> EventBus) : Spek ( { val eventBus = factory() describe("publishing events") { // ... tests appear here } } ) class SyncPubSubFactorySpec : PubSubTck(::EventBus) class AsyncPubSubFactorySpec : PubSubTck({ AsyncEventBus(newSingleThreadExecutor()) })
DIAGRAMMED ASSERTIONS#1 on my Spek wishlist!
"POWER ASSERT" – SPOCK
expect: order.user.firstName == "Rob"
"POWER ASSERT" – SPOCK
order.user.firstName == "Rob" | | | | | | rob false | | 1 difference (66% similarity) | | (r)ob | | (R)ob | [firstName:rob, lastName:fletcher] Order<#3243627>
DIAGRAMMED ASSERTIONS – SCALATEST
assert(order.getUser.getFirstName == "Rob") | | | | | | rob false | User<firstName:rob, lastName:fletcher> Order<#3243627>
BAY AREA KOTLIN USER GROUP
May 26 / 6pmNetflix in Los Gatos
➤ Netflix Engineering Tools — Kotlin Spring Cloud Extensions
meetup.com/Bay-Area-Kotlin-User-Group