Excuse me, sir, do you have a moment to talk about tests in Kotlin

98
Excuse me, sir, do you have a moment to talk about tests in Kotlin? Leonid Rudenko

Transcript of Excuse me, sir, do you have a moment to talk about tests in Kotlin

Excuse me, sir, do you have a moment to talk about tests in Kotlin?—Leonid Rudenko

Why?—

_2

Why?—

_3

Why?—

Selenium Camp 2016

#4MakeYourAutomationier

_4

What’s going on here—

• What is Kotlin?• Problems Kotlin solves• Demo

Excuse me, sir, do you have a moment to talk about tests in Kotlin? _5

What’s going on here—

• What is Kotlin?• Problems Kotlin solves• Demo

Excuse me, sir, do you have a moment to talk about tests in Kotlin? _6

Kotlin is...—

• JVM language from JetBrains – Java 6+

1. What is Kotlin? _7

Kotlin is...—

• JVM language• Statically typed

1. What is Kotlin? _8

Kotlin is...—

• JVM language• Statically typed• Multi-paradigm – OOP & functional

1. What is Kotlin? _9

Kotlin is...—

• JVM language• Statically typed• Multi-paradigm• Pragmatic

1. What is Kotlin? _10

Kotlin is...—

• JVM language• Statically typed• Multi-paradigm• Pragmatic• Democratic

1. What is Kotlin? _11

Kotlin is...—

• JVM language• Statically typed• Multi-paradigm• Pragmatic• Democratic• Safe

1. What is Kotlin? _12

Kotlin is...—

• JVM language• Statically typed• Multi-paradigm• Pragmatic• Democratic• Safe• Concise

1. What is Kotlin? _13

Brevityisthesisteroftalent.- AntonChekhov-

Kotlin is...—

• JVM language• Statically typed• Multi-paradigm• Pragmatic• Democratic• Safe• Concise• Interoperable

1. What is Kotlin? _14

Kotlin is...—

• JVM language• Statically typed• Multi-paradigm• Pragmatic• Democratic• Safe• Concise• Interoperable

1. What is Kotlin? _15

Kotlin 1.0—

• 15 Feb 2016 – backward compatibility

1. What is Kotlin? _16

Kotlin 1.0—

• 15 Feb 2016• kotlinc, Intellij IDEA (plugin), Eclipse (plugin), NetBeans (plugin)

1. What is Kotlin? _17

Kotlin 1.0—

• 15 Feb 2016• kotlinc, Intellij IDEA (plugin), Eclipse (plugin), NetBeans (plugin)• Open source https://github.com/jetbrains/kotlin

1. What is Kotlin? _18

1. What is Kotlin? _19

_20

Google Trends: Kotlin 1y—

1. What is Kotlin? _21

Google Trends: Kotlin vs Groovy 1y—

1. What is Kotlin? _22

Where Kotlin is used—

• JetBrains products

1. What is Kotlin? _23

Where Kotlin is used—

• JetBrains products• Android

1. What is Kotlin? _24

Where Kotlin is used—

• JetBrains products• Android• Server & Desktop

1. What is Kotlin? _25

Where Kotlin is used—

• JetBrains products• Android• Server & Desktop• Gradle3.0 https://github.com/gradle/gradle-script-kotlin

1. What is Kotlin? _26

Where Kotlin is used—

• JetBrains products• Android• Server & Desktop• Gradle3.0• (Web) Test Automation

1. What is Kotlin? _27

Test Automation: why Kotlin?—• Syntax similar to Java

1. What is Kotlin? _28

Test Automation: why Kotlin?—• Syntax similar to Java

• Clean test codeConcisenessEasy to read == easy to understandCollective code ownership, effective code review

1. What is Kotlin? _29

Test Automation: why Kotlin?—• Syntax similar to Java

• Clean test codeConcisenessEasy to read == easy to understandCollective code ownership, effective code review

• Safe test code

1. What is Kotlin? _30

What’s going on here—

• What is Kotlin?• Problems Kotlin solves• Demo

Excuse me, sir, do you have a moment to talk about tests in Kotlin? _31

Kotlin features—• Extension functions

• Data classes

• Lambda functions

• Smart cast

• Type inference

• Null safety

2. Problems Kotlin solves _32

1. Problem: Maps and Lists in Java—

// JavaMap<Integer, Credentials> users = new HashMap<>();users.put(1, new Credentials("vasya", "123456"));users.put(2, new Credentials("johny", "qwerty"));users.put(3, new Credentials("admin", "admin"));

List<Integer> responseCodes = new ArrayList<>();responseCodes.add(200);responseCodes.add(302);

2. Problems Kotlin solves _33

1. Solution: Kotlin collections—

// Kotlinval users = mapOf(

1 to Credentials("vasya", "123456"),2 to Credentials("johny", "qwerty"),3 to Credentials("admin", "admin"))

val responseCodes = listOf(200, 302)

2. Problems Kotlin solves _34

1. Collections: Map—

// Kotlinval users = mapOf(

1 to Credentials("vasya", "123456"),2 to Credentials("johny", "qwerty"),3 to Credentials("admin", "admin"))

Map<Integer, Credentials>newusers.put(4, Credentials("...", "..."))

2. Problems Kotlin solves _35

1. Collections: Traversing a map—

// Javafor (Map.Entry<Integer, Credentials> pair : users.entrySet()) {

System.out.println(pair.getKey() + "->" + pair.getValue());}

// Kotlinfor ((id, creds) in users) {

println("$id->$creds")}

2. Problems Kotlin solves _36

1. Collections: forEach, filters, sorting...—

// Kotlinval link = driver.findElements("a").firstOrNull {

it.text == "Selenium Camp"}

2. Problems Kotlin solves _37

1. Collections: Java & Groovy—

• Java 7

• Java 8 (Stream API)

• Groovy

2. Problems Kotlin solves _38

1. Collections: forEach, filters, sorting...—

2. Problems Kotlin solves _39

// Kotlinval link = driver.findElements("a").firstOrNull {

it.text == "Selenium Camp"}

2. Problem: framework can’t do what you need it to do—

// Javapublic static List<WebElement> findElements(WebDriver driver, String selector) {

return driver.findElements(By.cssSelector(selector));}

findElements(driver, "a");

2. Problems Kotlin solves _40

2. Problem: framework can’t do what you need it to do—

2. Problems Kotlin solves _41

2. Solution: Extension functions—

// Kotlinfun WebDriver.findElements(selector: String): List<WebElement>{

return this.findElements(By.cssSelector(selector))}

driver.findElements("a")

2. Problems Kotlin solves _42

2. Extension functions—

// Kotlinfun WebDriver.findElements(selector: String): List<WebElement>{

return this.findElements(By.cssSelector(selector))}

driver.findElements("a")

2. Problems Kotlin solves _43

2. Extension functions—

// Kotlinfun WebDriver.findElements(selector: String): List<WebElement>{

return this.findElements(By.cssSelector(selector))}

driver.findElements("a")

2. Problems Kotlin solves _44

2. Extension functions—

// Kotlinfun WebDriver.findElements(selector: String): List<WebElement>{

return this.findElements(By.cssSelector(selector))}

driver.findElements("a")

2. Problems Kotlin solves _45

2. Extension functions: Java & Groovy—

• Java

• Groovy (Extension Modules)

2. Problems Kotlin solves _46

3. Problem: small classes are not small—// Javapublic class Credentials {

private final String username;private final String password;

}

2. Problems Kotlin solves _47

3. Problem: small classes are not small—// Javapublic class Credentials {

private final String username;private final String password;

public Credentials(String username, String password) {this.username = username;this.password = password;

}}

2. Problems Kotlin solves _48

3. Problem: small classes are not small—// Javapublic class Credentials {private final String username;private final String password;

public Credentials(String username, String password) {this.username = username;this.password = password;

}

public String getUsername() { return username; }public String getPassword() { return password; }

}

2. Problems Kotlin solves _49

3. Problem: small classes are not small—// Javapublic class Credentials {

private final String username;private final String password;

public Credentials(String username, String password) {this.username = username;this.password = password;

}

public String getUsername() { return username; }public String getPassword() { return password; }

@Overridepublic String toString() {

return username + '/' + password;}

}

2. Problems Kotlin solves _50

3. Problem: small classes are not small—// Javapublic class Credentials {

private final String username;private final String password;

public Credentials(String username, String password) {this.username = username;this.password = password;

}

public String getUsername() { return username; }public String getPassword() { return password; }

@Overridepublic String toString() {

return username + '/' + password;}

@Overridepublic boolean equals(Object o) {

if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Credentials that = (Credentials) o;if (username != null ? !username.equals(that.username) : that.username != null) return false;return password != null ? password.equals(that.password) : that.password == null;

}@Overridepublic int hashCode() {

int result = username != null ? username.hashCode() : 0;return 31 * result + (password != null ? password.hashCode() : 0);

}}

2. Problems Kotlin solves _51

3. Problem: 27 lines—// Javapublic class Credentials {

private final String username;private final String password;

public Credentials(String username, String password) {this.username = username;this.password = password;

}

public String getUsername() { return username; }public String getPassword() { return password; }

@Overridepublic String toString() {

return username + '/' + password;}

@Overridepublic boolean equals(Object o) {

if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Credentials that = (Credentials) o;if (username != null ? !username.equals(that.username) : that.username != null) return false;return password != null ? password.equals(that.password) : that.password == null;

}@Overridepublic int hashCode() {

int result = username != null ? username.hashCode() : 0;return 31 * result + (password != null ? password.hashCode() : 0);

}}

2. Problems Kotlin solves _52

3. Solution: direct to Kotlin – 18 lines—// Javapublic class Credentials {

private final String username;private final String password;

public Credentials(String username, String password) {this.username = username;this.password = password;

}

public String getUsername() { return username; }public String getPassword() { return password; }

@Overridepublic String toString() {

return username + '/' + password;}

@Overridepublic boolean equals(Object o) {

if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Credentials that = (Credentials) o;if (username != null ? !username.equals(that.username) : that.username != null)

return false;return password != null ? password.equals(that.password) : that.password == null;

}@Overridepublic int hashCode() {

int result = username != null ? username.hashCode() : 0;return 31 * result + (password != null ? password.hashCode() : 0);

}}

2. Problems Kotlin solves _53

// Kotlinclass Credentials {

private val username: Stringprivate val password: String

constructor(username: String, password: String) {this.username = usernamethis.password = password

}

fun getUsername(): String { return username }fun getPassword(): String { return password }

override fun toString() = username + '/' + password

override fun equals(other: Any?): Boolean {if (this === other) return trueif (other?.javaClass != javaClass) return falseother as Credentialsreturn username == other.username && password == other.password

}

override fun hashCode() = 31 * username.hashCode() + password.hashCode()

}

3. Solution: remove getters – 16 lines —// Kotlinclass Credentials {val username: Stringval password: String

constructor(username: String, password: String) {this.username = usernamethis.password = password

}

//fun getUsername(): String { return username }//fun getPassword(): String { return password }

override fun toString() = username + '/' + password

override fun equals(other: Any?): Boolean {if (this === other) return trueif (other?.javaClass != javaClass) return falseother as Credentialsreturn username == other.username && password == other.password

}

override fun hashCode() = 31 * username.hashCode() + password.hashCode()}

2. Problems Kotlin solves _54

3. Solution: primary constructor – 10 lines—// Kotlinclass Credentials(val username: String, val password: String) {//val username: String//val password: String

//constructor(username: String, password: String) {// this.username = username// this.password = password//}

override fun toString() = username + '/' + password

override fun equals(other: Any?): Boolean {if (this === other) return trueif (other?.javaClass != javaClass) return falseother as Credentialsreturn username == other.username && password == other.password

}

override fun hashCode() = 31 * username.hashCode() + password.hashCode()}

2. Problems Kotlin solves _55

3. Solution: data class – 1 line —// Kotlindata class Credentials(val username: String, val password: String) {//override fun toString() = username + '/' + password

//override fun equals(other: Any?): Boolean {// if (this === other) return true// if (other?.javaClass != javaClass) return false// other as Credentials// return username == other.username && password == other.password//}

//override fun hashCode() = 31 * username.hashCode() + password.hashCode()}

2. Problems Kotlin solves _56

3. Solution: Kotlin data classes—

// Kotlindata class Credentials(val username: String, val password: String)

val creds = Credentials("a", "b")println(creds.username) // acreds.username = "you can't do that"println(creds) // Credentials(username=a, password=b)println(creds == Credentials("a", "b")) // true

2. Problems Kotlin solves _57

3. Solution: Kotlin data classes—

// Kotlindata class Credentials(val username: String, val password: String) {

override fun toString(): String {return "$username/$password"

}

}

println(Credentials("one", "two")) // one/two

2. Problems Kotlin solves _58

3. Data classes: Java & Groovy—

• Java (Lombok https://projectlombok.org/)

• Groovy (@groovy.transform.Canonical)

2. Problems Kotlin solves _59

4. Problem: steps in Allure report—

// Javadriver.findElement("button").click();

2. Problems Kotlin solves _60

4. Problem: steps in Allure report—

// Java@Step("Click the button")public void clickButton() {

driver.findElement("button").click();}

clickButton();

2. Problems Kotlin solves _61

4. Solution: steps in Allure report—

// Java 8@Step("{0}")public void step(String title, Runnable code) {

code.run();}

step("Click the button", () -> {driver.findElement("button").click();

});

2. Problems Kotlin solves _62

4. Solution: steps in Allure report—

// Kotlin@Step("{0}")fun step(title: String, code: () -> Any) = code()

step("Click the button") {driver.findElement("button").click()

}

2. Problems Kotlin solves _63

4. Solution: just compare—

// Java 8step("Click the button", () -> {

// your code here});

// Kotlinstep("Click the button") {

// your code here}

2. Problems Kotlin solves _64

4. Steps in Allure report: Java & Groovy—

• Java 7

• Java 8

• Groovy

2. Problems Kotlin solves _65

5. Problem: checked exceptions—

// JavaURLDecoder.decode(param, "UTF-8");

2. Problems Kotlin solves _66

// JavaURLDecoder.decode(param, "UTF-8");

// KotlinURLDecoder.decode(param, "UTF-8")

5. Solution: no checked exceptions—

2. Problems Kotlin solves _67

5. Checked exceptions: Java & Groovy—

• Java

• Groovy

2. Problems Kotlin solves _68

6. Problem: unchecked cast—

// JavaObject results

= ((JavascriptExecutor) driver).executeScript("...");

2. Problems Kotlin solves _69

// JavaObject results

= ((JavascriptExecutor) driver).executeScript("...");if (results instanceof List) {

List<String> list = ((List<Object>) results).stream().filter(String.class::isInstance).map(String.class::cast).collect(toList());

}

6. Problem: unchecked cast—

2. Problems Kotlin solves _70

// JavaObject results

= ((JavascriptExecutor) driver).executeScript("...");if (results instanceof List) {

List<String> list = ((List<Object>) results)

}

6. Problem: unchecked cast—

2. Problems Kotlin solves _71

// Kotlinval results

= (driver as JavascriptExecutor).executeScript("...")if (results is List<*>) {

val list = results.filterIsInstance<String>() }

6. Solution: Kotlin smart cast—

2. Problems Kotlin solves _72

// Kotlinval results

= (driver as JavascriptExecutor).executeScript("...")if (results is List<*>) {

val list = results.filterIsInstance<String>() }

6. Solution: Kotlin smart cast—

2. Problems Kotlin solves _73

6. Unchecked cast: Java & Groovy—

• Java

• Groovy

2. Problems Kotlin solves _74

7. Problem: Java is verbose—

2. Problems Kotlin solves _75

7. Solution: Kotlin syntactic sugar—

// JavaactualText.equals(expectedText)

// KotlinactualText == expectedText

2. Problems Kotlin solves _76

7. Solution: String templates—

// JavaString s = "date: " + date + " and author: " + USER.getName();String s =

format("date: %s and author: %s", date, USER.getName());

// Kotlinval s = "date: $date and author: ${USER.name}"

2. Problems Kotlin solves _77

7. Solution: ranges—

// Javafor (int i = 0; i <= 10; i += 2)

// Kotlinfor (i in 0..10 step 2)

2. Problems Kotlin solves _78

7. Solution: Kotlin rich standard library—

// Java!list.isEmpty()

// Kotlinlist.isNotEmpty()

2. Problems Kotlin solves _79

7. Solution: Kotlin type inference—

// Javafinal int i = 0;final String s = "abc";final List<String> list = new ArrayList<>();

// Kotlinval i = 0val s = "abc"val list = listOf("a", "b", "c")

2. Problems Kotlin solves _80

7. Verbosity: Java & Groovy—

• Java

• Groovy

2. Problems Kotlin solves _81

8. Problem: java.lang.NullPointerException—

2. Problems Kotlin solves _82

8. Solution: Null safety—

var username: Stringusername = null // compilation error

2. Problems Kotlin solves _83

8. Null safety—

var username: Stringusername = null // compilation error

var username: String?username = null // ok

2. Problems Kotlin solves _84

8. Null safety—

var username: String // non-nullable Stringusername = null

var username: String? // nullable Stringusername = null

2. Problems Kotlin solves _85

8. Null safety: safe call—

var username: String? = "Vasya"var count = username.length // compilation error

2. Problems Kotlin solves _86

8. Null safety: safe call—

var username: String? = "Vasya"var count = username?.length // ok, count is 5

username = nullvar count = username?.length // ok, count is null

2. Problems Kotlin solves _87

8. Null safety: Elvis operator—

input.sendKeys(username ?: "Guest")

var images = findAllImagesOnPage()?: throw AssertionError("No images")

2. Problems Kotlin solves _88

?:

8. Null safety: Java & Groovy—

• Null safety: Java (Optional<T> in Java8), Groovy• Safe call: Java, Groovy• Elvis operator: Java, Groovy

2. Problems Kotlin solves _89

Java vs Groovy vs Kotlin—

2. Problems Kotlin solves _90

1 2 3 4 5 6 7 8

Java7 – – – – – – – –

Java8 ± – – + – – – –

Groovy + ± + + + – + –

Kotlin + + + + + + + +

Why not Groovy?—

• Not statically typed: runtime bugs

• Not statically typed: performance

• Not statically typed: IDE support

• No null safety

2. Problems Kotlin solves _91

What’s going on here—

• What is Kotlin?• Problems Kotlin solves• Demo

Excuse me, sir, do you have a moment to talk about tests in Kotlin? _92

Example test project in Kotlin—

• JUnit http://junit.org/junit4/

• Html Elements https://github.com/yandex-qatools/htmlelements

• Allure Framework https://github.com/allure-framework/

• Gradle https://gradle.org/

• gradle-docker-plugin https://github.com/bmuschko/gradle-docker-plugin

3. Demo _93

https://github.com/leonsabr/seleniumcamp-kotlin-demo—

3. Demo _94

• Kotlin + { Gradle, JUnit, Selenium, Html Elements, Allure } = OK

https://github.com/leonsabr/seleniumcamp-kotlin-demo—

3. Demo _95

• Kotlin + { Gradle, JUnit, Selenium, Html Elements, Allure }• Java interoperability

https://github.com/leonsabr/seleniumcamp-kotlin-demo—

3. Demo _96

java kotlin ∆main 670 434 35,2%test 92 84 8,7%total 762 518 32%

• Kotlin + { Gradle, JUnit, Selenium, Html Elements, Allure }• Java interoperability• Conciseness (lines of code)

Useful links—

• Reference http://kotlinlang.org/docs/reference/

• List of Kotlin resources https://kotlin.link/

• Try Kotlin online http://try.kotl.in/

• Slack https://kotlinlang.slack.com/

_97

Thank you for your attention—

jetbrains.com

[email protected]@leonsabr