Download - Kotlin, Spek and tests
![Page 1: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/1.jpg)
Kotlin, Spek and testsHow to use Kotlin for your test suite,and why you might want to
Konrad Morawski
![Page 3: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/3.jpg)
http://kotlinlang.org/
● first unveiled in 2011● 1.0 only just released! (on February 15)
● 100% interoperability with Java
● backed by JetBrains (IntelliJ Idea ➠ Android Studio)
● open-source
● available outside of, but suited for Android● supported in Android Studio (IDE plugins)
● resembling: Swift, Scala, C#?
![Page 4: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/4.jpg)
Kotlin in action
JavaString str = "type value";
int add(int a, int b)
Kotlinval str: String = "value: type"
val str = "value (inferred...)"
fun add(x: Int, y: Int): Int
![Page 5: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/5.jpg)
Lambdas
val sum: (Int, Int) -> Int = { x, y -> x + y }
sum(1, 2) == 3 // true
fun apply(i: Int, f: (Int -> Int) = f(i)
apply(2, { x -> x + 25})
apply(2) { x -> x + 25}
listOf(1, 2, 3).filter { it > 2 }
button.setOnClickListener {
Log.d("clicked!")
}
![Page 6: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/6.jpg)
Top 10 words, at least 3 characters long (Java)Iterable<String> getTopWords(String text) {
String[] words = text.split(" ");
Map<String, Integer> indexed = new HashMap<>();
for (String word : words) {
if (word.length() <= 3) continue;
if (!indexed.containsKey(word)) indexed.put(word, 0);
indexed.put(word, indexed.get(word) + 1);
}
List<Map.Entry<String, Integer>> sorted = new ArrayList<>(indexed.entrySet());
Collections.sort(sorted, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> one, Map.Entry<String, Integer> another) {
return another.getValue().compareTo(one.getValue());
}});
List<String> topTen = new ArrayList<>();
for (Map.Entry<String, Integer> top : sorted) {
topTen.add(top.getKey());
if (topTen.size() == 10)
break;
}
return topTen;
}
![Page 7: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/7.jpg)
Top 10 words, at least 3 characters long (Java)Iterable<String> getTopWords(String text) {
String[] words = text.split(" ");
Map<String, Integer> indexed = new HashMap<>();
for (String word : words) {
if (word.length() <= 3) continue;
if (!indexed.containsKey(word)) indexed.put(word, 0);
indexed.put(word, indexed.get(word) + 1);
}
List<Map.Entry<String, Integer>> sorted = new ArrayList<>(indexed.entrySet());
Collections.sort(sorted, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> one, Map.Entry<String, Integer> another) {
return another.getValue().compareTo(one.getValue());
}});
List<String> topTen = new ArrayList<>();
for (Map.Entry<String, Integer> top : sorted) {
topTen.add(top.getKey());
if (topTen.size() == 10)
break;
}
return topTen;
}
![Page 8: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/8.jpg)
Top 10 words, at least 3 characters long (Java)Iterable<String> getTopWords(String text) {
String[] words = text.split(" ");
Map<String, Integer> indexed = new HashMap<>();
for (String word : words) {
if (word.length() <= 3) continue;
if (!indexed.containsKey(word)) indexed.put(word, 0);
indexed.put(word, indexed.get(word) + 1);
}
List<Map.Entry<String, Integer>> sorted = new ArrayList<>(indexed.entrySet());
Collections.sort(sorted, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> one, Map.Entry<String, Integer> another) {
return another.getValue().compareTo(one.getValue());
}});
List<String> topTen = new ArrayList<>();
for (Map.Entry<String, Integer> top : sorted) {
topTen.add(top.getKey());
if (topTen.size() == 10)
break;
}
return topTen;
}
![Page 9: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/9.jpg)
Iterable<String> getTopWords(String text) {
String[] words = text.split(" ");
Map<String, Integer> indexed = new HashMap<>();
for (String word : words) {
if (word.length() <= 3) continue;
if (!indexed.containsKey(word)) indexed.put(word, 0);
indexed.put(word, indexed.get(word) + 1);
}
List<Map.Entry<String, Integer>> sorted = new ArrayList<>(indexed.entrySet());
Collections.sort(sorted, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> one, Map.Entry<String, Integer> another) {
return another.getValue().compareTo(one.getValue());
}});
List<String> topTen = new ArrayList<>();
for (Map.Entry<String, Integer> top : sorted) {
topTen.add(top.getKey());
if (topTen.size() == 10)
break;
}
return topTen;
}
Top 10 words, at least 3 characters long (Kotlin)fun getTopWords(text: String): Iterable<String> {
val words = text.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val indexed = HashMap<String, Int>()
for (word in words) {
if (word.length <= 3) continue
if (!indexed.containsKey(word)) indexed.put(word, 0)
indexed.put(word, indexed[word]!! + 1)
}
val sorted = ArrayList(indexed.entries)
Collections.sort(sorted) { one, another -> another.value.compareTo(one.value) }
val topTen = ArrayList<String>()
for (top in sorted) {
topTen.add(top.key)
if (topTen.size == 10) break
}
return topTen
}
![Page 10: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/10.jpg)
Top 10 words, at least 3 characters long (Kotlin)fun getTopWords(text: String): Iterable<String> {
val words = text.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val indexed = HashMap<String, Int>()
for (word in words) {
if (word.length <= 3) continue
if (!indexed.containsKey(word)) indexed.put(word, 0)
indexed.put(word, indexed[word]!! + 1)
}
val sorted = ArrayList(indexed.entries)
Collections.sort(sorted) { one, another -> another.value.compareTo(one.value) }
val topTen = ArrayList<String>()
for (top in sorted) {
topTen.add(top.key)
if (topTen.size == 10) break
}
return topTen
}
![Page 11: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/11.jpg)
Top 10 words, at least 3 characters long (Kotlin)fun getTopWords(text: String): Iterable<String> {
val words = text.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val indexed = HashMap<String, Int>()
for (word in words) {
if (word.length <= 3) continue
if (!indexed.containsKey(word)) indexed.put(word, 0)
indexed.put(word, indexed[word]!! + 1)
}
val sorted = ArrayList(indexed.entries)
Collections.sort(sorted) { one, another -> another.value.compareTo(one.value) }val topTen = ArrayList<String>()
for (top in sorted) {
topTen.add(top.key)
if (topTen.size == 10) break
}
return topTen
}
![Page 12: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/12.jpg)
Top 10 words, at least 3 characters long (Kotlin)Collections.sort(sorted) { one, another -> another.value.compareTo(one.value) }
![Page 13: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/13.jpg)
Top 10 words, at least 3 characters longCollections.sort(sorted) { one, another -> another.value.compareTo(one.value) }
new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> one, Map.Entry<String, Integer> another) {
return another.getValue().compareTo(one.getValue());
}
});
THIS ISN'T NORMAL.
BUT IN JAVA IT IS.
![Page 14: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/14.jpg)
Top 10 words, at least 3 characters long (Kotlin)fun getTopWords(text: String): Iterable<String> {
val words = text.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val indexed = HashMap<String, Int>()
for (word in words) {
if (word.length <= 3) continue
if (!indexed.containsKey(word)) indexed.put(word, 0)
indexed.put(word, indexed[word]!! + 1)
}
val sorted = ArrayList(indexed.entries)
Collections.sort(sorted) { one, another -> another.value.compareTo(one.value) }
val topTen = ArrayList<String>()
for (top in sorted) {
topTen.add(top.key)
if (topTen.size == 10) break
}
return topTen
}
![Page 15: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/15.jpg)
Top 10 words, at least 3 characters long (idiomatic Kotlin)fun getTopWords(text: String): Iterable<String> = text
.splitToSequence(" ")
.filter { it.length > 3 }
.groupBy { it }
.asIterable()
.sortedByDescending { it.value.count() }
.take(10)
.map { it.key }
![Page 16: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/16.jpg)
Top 10 words, at least 3 characters long (idiomatic Kotlin)
fun getTopWords(text: String): Iterable<String> = text
.splitToSequence(" ")
.filter { it.length > 3 }
.groupBy { it }
.asIterable()
.sortedByDescending { it.value.count() }
.take(10)
.map { it.key }
![Page 17: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/17.jpg)
Top 10 words, at least 3 characters long (lambdas).filter { it.length > 3 }
.filter { word -> word.length > 3 }
![Page 18: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/18.jpg)
Extension functions
private fun String.last(): Char {return this[this.length - 1];
}
fun Activity.toast(msg: String) = Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
inline fun <T> Iterable<T>.none(predicate: (T) -> Boolean): Boolean {for (element in this) if (predicate(element)) return falsereturn true
}
listOf(1, 2, 3).none { number -> number < 0 } // true
![Page 19: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/19.jpg)
Iterations
for ((key, value) in map) for ((index, value) in list. withIndex())
Ranges
for (i in 1..10)for (i in 4 downTo 1)for (i in 1.0..2.0 step 0.3)val fontSizes = (12..22) map { it.toFloat() }
Infix functions
mapOf(1 to "one", 2 to "two")
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
public infix fun Int.downTo(to: Int): IntProgression { return IntProgression.fromClosedRange(this, to, -1)}
![Page 20: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/20.jpg)
Null safety
if (user != null) {if (address != null) {
// ...
user?.address?.street
val id: String? = "123"id.length // won't compileid?.length // ok
if (id != null)id.length // ok again
id?.length ?: -1 // ok and more idiomatic
fun acceptId(id: String) // signature indicates a non-null valueacceptId(id) // won't compile until ensured id isn't null
![Page 21: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/21.jpg)
Smart casts
if (x is Int) { val y = x * 5 // compiles!
}
when (outcome) { // some object...is SomeData -> onResult(outcome) // onResult(SomeData), no castingis Exception -> onError(outcome) // again no castingelse -> Log.d("?", "weird")
}
Data classes
data class User(val id: Int, val name: String )// that's it! // 1. immutable. // 2. equals, hashCode, toString out of the box.// 3. deep copies: user.copy(name = "Another name")// 4. named parameters!
![Page 22: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/22.jpg)
Operator overloading
class Money(val amount: Int) {operator fun plus(money: Money): Money =
Money(this.amount + money.amount)}
Money(1) + Money(2) // builds, equals Money(3)
Also starring● reified generics
● language-level support for delegation pattern
● easy immutability
● dynamic types
● ...
![Page 23: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/23.jpg)
DSL in Kotlin. Example #1: dealing with Android APIs
// extension functioninline fun SharedPreferences.edit(
func: SharedPreferences.Editor.() -> Unit) {val editor = edit()editor.func()editor.apply()
}
// and then in code...preferences.edit{
putString("some_key", "value")// etc.
}
⬆ Never again forget calling apply().
![Page 24: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/24.jpg)
DSL in Kotlin. Example #2: dealing with Android APIs
// extension functioninline fun SQLiteDatabase.inTransaction(
func: SQLiteDatabase.() -> Unit) {beginTransaction()try {
func() // executing the function passed as a parameter setTransactionSuccessful()
} finally { endTransaction()
}}
// and then in code...db.inTransaction {
delete("users", "id = ?", arrayOf(19))// etc. never missing setTransactionSuccessful!
}
![Page 25: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/25.jpg)
DSL in Kotlin. Type-safe Groovy-style builders. Example #3: Anko
verticalLayout {padding = dip(30)editText {
hint = "Name"textSize = 24f
}editText {
hint = "Password"textSize = 24f
}button("Login") {
textSize = 26f}
}https://github.com/Kotlin/anko
![Page 26: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/26.jpg)
DSL in Kotlin. Example #4: anything you want
expect { Romanizer().convert(it) }.toTransform(
10 to "X",61 to "CLXI",1999 to "MCMCDIX")
// not that hard to set upfun Spek.expect(func: (Int) -> String) = this to func
private fun Pair<Spek, Function1<Int, String>>.toTransform(vararg pairs: Pair<Int, String>) {val function = this.secondval map = mapOf(*pairs)this.first.givenData(map.keys) {
on("converted to Roman numerals") {val actual = function(it)it("should be equal to ${map[it]}") {
shouldEqual(map[it], actual)}}}}
![Page 27: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/27.jpg)
PERSPECTIVES FOR USING KOTLIN
➕ Better, more modern and expressive
➕ Full access to Java goodness
➖ Your colleagues
➖ Your boss
➖ Your boss’s customer
![Page 28: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/28.jpg)
WHAT ARE UNIT TESTS FOR?
▪ Executable documentation
▪ Aiding good design
(single responsibility; TDD; edge cases)
▪ Tighter feedback loop
▪ Bug detection
![Page 29: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/29.jpg)
COMMON PROBLEMS WITH UNIT TESTS
▪ What tests?“We would not trust a doctor who didn’t wash his or her hands. (...)No-one should trust software developed without unit tests.”
Martin Fowler
![Page 30: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/30.jpg)
COMMON PROBLEMS WITH UNIT TESTS
▪ What tests? ▪ They're dead
![Page 31: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/31.jpg)
KEEPING YOUR TESTS TIDY
public void testTaskPresenter() {task.setRecipient(OWN_JID);TaskScreen screen = mock(TaskScreen.class);TaskPresenter presenter = new TaskPresenter(screen, OWN_JID);presenter.setTask(task);presenter.setRoom(Room.getEmpty());presenter.initViews();verify(screen).setResponseEnabled(true);
}
What does this test check?
![Page 32: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/32.jpg)
KEEPING YOUR TESTS TIDY
public void testInitViews() {task.setRecipient(OWN_JID);TaskScreen screen = mock(TaskScreen.class);TaskPresenter presenter = new TaskPresenter(screen, OWN_JID);presenter.setTask(task);presenter.setRoom(Room.getEmpty());presenter.initViews();verify(screen).setResponseEnabled(true);
}
What does this test check?
![Page 33: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/33.jpg)
KEEPING YOUR TESTS TIDY
public void testTaskWithNoResponse_iAmReceiver_responseButtonShown() {task.setRecipient(OWN_JID);TaskScreen screen = mock(TaskScreen.class);TaskPresenter presenter = new TaskPresenter(screen, OWN_JID);presenter.setTask(task);presenter.setRoom(Room.getEmpty());presenter.initViews();verify(screen).setResponseEnabled(true);
}
What does this test check?
![Page 34: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/34.jpg)
KEEPING YOUR TESTS TIDY
testTaskWithNoResponse_iAmReceiver_responseButtonShown()http://osherove.com/
![Page 35: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/35.jpg)
KEEPING YOUR TESTS TIDY
public void testTaskWithNoResponse_iAmReceiver_responseButtonShown() {task.setRecipient(OWN_JID);TaskScreen screen = mock(TaskScreen.class);TaskPresenter presenter = new TaskPresenter(screen, OWN_JID);presenter.setTask(task);presenter.setRoom(Room.getEmpty());presenter.initViews();verify(screen).setResponseEnabled(true);
}
What does this test check?
![Page 36: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/36.jpg)
KEEPING YOUR TESTS TIDY
public void testTaskWithNoResponse_iAmReceiver_responseButtonShown() {// ARRANGEtask.setRecipient(OWN_JID);TaskScreen screen = mock(TaskScreen.class);TaskPresenter presenter = new TaskPresenter(screen, OWN_JID);presenter.setTask(task);presenter.setRoom(Room.getEmpty());
// ACTpresenter.initViews();
// ASSERTverify(screen).setResponseEnabled(true);
}
What does this test check?
![Page 37: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/37.jpg)
KEEPING YOUR TESTS TIDY
given("a task with no response and assigned to myself") {val screen = mock(TaskScreen::class)val presenter = TaskPresenter(screen)presenter.task = Task().apply { recipient = OWN_JID }presenter.room = Room.empty()
on("presenter initializes views") {presenter.initViews()
it("should enable the response button") {verify(screen).setResponseEnabled(true)
}}
}
What does this test check?
![Page 38: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/38.jpg)
KEEPING YOUR TESTS TIDY
given("a task with no response and assigned to myself") {val screen = mock(TaskScreen::class)val presenter = TaskPresenter(screen)presenter.task = Task().apply { recipient = OWN_JID }presenter.room = Room.empty()
on("presenter initializes views") {presenter.initViews()
it("should enable the response button") {verify(screen).setResponseEnabled(true)
}}
}
What does this test check?
![Page 39: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/39.jpg)
KEEPING YOUR TESTS TIDY
What does this test check?
![Page 40: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/40.jpg)
ARRANGE(unit of work)
ACT(state under test)
ASSERT(expected behaviour)
GIVEN...initial context
WHEN...event occurs
THEN...ensure some outcomes
unit tests BDD
![Page 41: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/41.jpg)
Testing on bulk dataval data = listOf( "0" to "0th", "1" to "1st", "2" to "2nd" ...)givenData(data) { val (input, expected) = it on("calling ordinalize on string", { val actual = input.ordinalize() it("should become ${it.component2()}", { shouldEqual(expected, actual) }) })}
https://github.com/MehdiK/Humanizer.jvm
![Page 42: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/42.jpg)
Pending and skip
on("API does not respond") {it("should retry 3 times") {
pending("not implemented yet")}
it ("should display an error") {skip("obsolete now")// …
}}
![Page 43: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/43.jpg)
...combine with other perks of Kotlin
given("a pub") { val pub = Pub()
on("trying to buy beer") { val customer = Guy("Robert")
val underage = customer.copy(age = 14) it("refuses to serve minors like $underage") { shouldBeFalse(pub.sellsBeer(underage) }
val adult = customer.copy(age = 18) it("sells to adults like $adult") { shouldBeTrue(pub.sellsBeer(adult)) } }
![Page 44: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/44.jpg)
...combine with other perks of Kotlin
given("a pub") { val pub = Pub()
on("trying to buy beer") { val customer = Guy("Robert")
val underage = customer.copy(age = 14) it("refuses to serve minors like $underage") { shouldBeFalse(pub.sellsBeer(underage) }
val adult = customer.copy(age = 18) it("sells to adults like $adult") { shouldBeTrue(pub.sellsBeer(adult)) } }
![Page 45: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/45.jpg)
IT’S DIFFICULT TO SET UP, RIGHT?
![Page 46: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/46.jpg)
YOU BE THE JUDGE
(* )
![Page 47: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/47.jpg)
ONCE YOU’VE GOT THE PLUGIN
![Page 48: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/48.jpg)
GRADLE SCRIPTS UPDATED AUTOMATICALLY
![Page 49: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/49.jpg)
AND SPEK:
All set.
![Page 50: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/50.jpg)
MORE RESOURCES▪ https://youtu.be/A2LukgT2mKc - Android Development with Kotlin (Jake Wharton)▪ https://goo.gl/AQB7af - more detailed summary (same author)▪ http://blog.jetbrains.com/kotlin/2016/01/kotlin-digest-2015/#more-3400 - selection of
articles▪ http://www.javacodegeeks.com/2016/01/mimicking-kotlin-builders-java-python.html
on typesafe data builders (DSL)▪ http://antonioleiva.com/kotlin-awesome-tricks-for-android/ ▪ https://medium.com/@CodingDoug/kotlin-android-a-brass-tacks-experiment-part-4-
4b7b501fa457#.4xh886p73 - from a Google employee, a series of 4 parts (as of now)
▪ http://beust.com/weblog/2015/10/30/exploring-the-kotlin-standard-library/▪ https://github.com/nhaarman/mockito-kotlin - helper functions to work with Mockito
![Page 51: Kotlin, Spek and tests](https://reader034.vdocuments.site/reader034/viewer/2022051318/589cf5c31a28abcc258b5d1f/html5/thumbnails/51.jpg)
Konrad Morawski
Software Engineer Specialist
Thank you!