25. _25
2. Problem: framework can’t do what you need it to do
—
// Java
public static void waitForElement(HtmlElement element, long
timeout) {
...
}
waitForElement(link, 10);
link.click();
34. // Java
public class Credentials {
private final String username;
private final String password;
}
_34
3. Problem: small classes are not small
—
35. // Java
public class Credentials {
private final String username;
private final String password;
public Credentials(String username, String password) {
this.username = username;
this.password = password;
}
}
_35
3. Problem: small classes are not small
—
36. // Java
public 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; }
}
_36
3. Problem: small classes are not small
—
37. // Java
public 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; }
@Override
public String toString() {
return username + '/' + password;
}
}
_37
3. Problem: small classes are not small
—
38. // Java
public 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; }
@Override
public String toString() {
return username + '/' + password;
}
@Override
public 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;
}
@Override
public int hashCode() {
int result = username != null ? username.hashCode() : 0;
return 31 * result + (password != null ? password.hashCode() : 0);
}
}
_38
3. Problem: small classes are not small
—
39. // Java
public 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; }
@Override
public String toString() {
return username + '/' + password;
}
@Override
public 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;
}
@Override
public int hashCode() {
int result = username != null ? username.hashCode() : 0;
return 31 * result + (password != null ? password.hashCode() : 0);
}
}
_39
3. Problem: 27 lines
—
44. // Java
@Step("Click the button")
public void clickButton() {
driver.findElement("button").click();
}
clickButton();
_44
4. Problem: steps in Allure report
—
45. // Java 8
@Step("{0}")
public void step(String title, Runnable code) {
code.run();
}
step("Click the button", () -> {
driver.findElement("button").click();
});
_45
4. Solution: steps in Allure report
—
46. // Kotlin
@Step("{0}")
fun step(title: String, code: () -> Any) = code()
step("Click the button") {
driver.findElement("button").click()
}
_46
4. Solution: steps in Allure report
—
47. // Java 8
step("Click the button", () -> {
// your code here
});
// Kotlin
step("Click the button") {
// your code here
}
_47
4. Solution: just compare
—
76. • Not statically typed: runtime bugs
• Not statically typed: performance
• Not statically typed: IDE support
• No null safety
_76
Why not Groovy?
—
77. • Problems Kotlin solves
• Kotlin & Frameworks
• Demo
_77
What’s going on here
—
78. Kotlin ~ Java
—
// Kotlin
var counter: Int = 0
// Java
private int counter = 0;
public final int getCounter() {
return counter;
}
public final void setCounter(int newCounter) {
counter = newCounter;
}
_78
79. 1. JUnit 4
—
@Before fun `start browser`() { ... }
@Test fun `test name`() { ... }
@Ignore("ISSUE-9000")
@Test fun `ignored test`() { ... }
@After fun `quit browser`() { ... }
_79
92. 1. JUnit 4: @Parameters solution
—
_92
// Java
@RunWith(Parameterized.class)
class ParameterizedTest {
public final static class Companion {
public Collection<String[]> data() {
return asList(...);
}
}
public final static Companion Companion = new Companion();
@Parameters(name = "{0}")
public final static Collection<String[]> data() {
return Companion.data();
}
}
93. 1. JUnit 4: @Parameters solution
—
_93
// Java
@RunWith(Parameterized.class)
class ParameterizedTest {
public final static class Companion {
public Collection<String[]> data() {
return asList(...);
}
}
public final static Companion Companion = new Companion();
@Parameters(name = "{0}")
public final static Collection<String[]> data() {
return Companion.data();
}
}
94. 1. JUnit 4: @Parameters solution
—
_94
// Java
@RunWith(Parameterized.class)
class ParameterizedTest {
public final static class Companion {
public Collection<String[]> data() {
return asList(...);
}
}
public final static Companion Companion = new Companion();
@Parameters(name = "{0}")
public final static Collection<String[]> data() {
return Companion.data();
}
}
95. 1. JUnit 4: @Parameters solution
—
_95
// Java
@RunWith(Parameterized.class)
class ParameterizedTest {
public final static class Companion {
public Collection<String[]> data() {
return asList(...);
}
}
public final static Companion Companion = new Companion();
@Parameters(name = "{0}")
public final static Collection<String[]> data() {
return Companion.data();
}
}
96. 2. HtmlElements 1.*: element
—
_96
@FindBy(css = "form[name='LoginForm']")
class LoginForm : HtmlElement() {
@FindBy(css = "#username")
lateinit var usernameInput: HtmlElement
@FindBy(css = "#password")
lateinit var passwordInput: HtmlElement
@FindBy(xpath = ".//button")
lateinit var loginButton: HtmlElement
fun login(username: String, password: String) {
usernameInput.sendKeys(username)
passwordInput.sendKeys(password)
loginButton.click()
}
}
99. 2. HtmlElements 1.*: collection of elements
—
_99
// Kotlin
@FindBy(css = "a")
lateinit var links: List<HtmlElement>
...
links.forEach { ... }
100. 2. HtmlElements 1.*: collection of elements
—
_100
// Kotlin
@FindBy(css = "a")
lateinit var links: List<HtmlElement>
...
links.forEach { ... }
kotlin.UninitializedPropertyAccessException
101. 2. HtmlElements 1.*: collection of elements
—
_101
// Kotlin
@FindBy(css = "a")
lateinit var links: List<HtmlElement>
java.util.List<? extends
ru.yandex.qatools.htmlelements.element.HtmlElement>
102. 2. HtmlElements 1.*: collection of elements
—
_102
// Kotlin
@FindBy(css = "a")
lateinit var links: List<@JvmSuppressWildcards HtmlElement>
java.util.List<ru.yandex.qatools.htmlelements.element.HtmlElement>
• https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#variant-generics
103. 3. Allure
—
_103
// Kotlin
@Title("This is title")
@Description("This is description")
@Test fun test() { ... }
@Step("Change Home URL to {0}")
fun changeHomeURL(homeURL: String) { ... }
@Attachment(value = "{0}", type = "text/plain")
fun attachText(name: String = "text", text: String?) = text
107. 3. Allure: org.aspectj:aspectjweaver:1.8.10
—
_107
// Kotlin
links.forEach {
println(it.text)
}
java.lang.ClassFormatError: Invalid index 6 in
LocalVariableTable
• https://bugs.eclipse.org/bugs/show_bug.cgi?id=500796
108. 4. Selenide: $ is reserved
—
_108
// Kotlin
import com.codeborne.selenide.Selenide.$
Error: Kotlin: Qualified name must be a '.'-separated
identifier list