Зачем учить язык Kotlin?

Kotlin на текущий момент однозначно находится на пике популярности и может принести немало пользы в тестировании. Но не все так просто, в чем вы можете убедиться из этой статьи.

 

Откуда взялся этот ваш Kotlin?

Kotlin — достаточно молодой язык, который разрабатывается и спонсируется компанией JetBrains. Из открытых источников можно узнать, что в разработку языка было вложено более $15 млн, а сам язык — это еще один способ популяризовать компанию и еще больше повысить продажи для Idea.

Язык начал набирать популярность после того, как на конференции JavaOne 2015 Hans Dockter, CEO of Gradle, заявил, что Котлин получает официальную поддержку для написания Gradle билд-скриптов. Тогда он все еще был в бете, но новость всколыхнула всех неравнодушных. Волна хайпа начала подниматься уже в тот момент. На пике популярности язык оказался в мае этого года на конференции Google I/O, где было объявлено о том, что Котлин наряду с Java становится официальным языком разработки под платформу Android. Сразу же после этого весь Twitter был в постах о новом языке, появилась куча блог-постов с признаниями в любви ему. Представители JetBrains в различных источниках стали заявлять, что Kotlin — это будущее разработки на JVM.

В целом если смотреть на ситуацию здраво, то причины хайпа вполне понятны. Джава развивается слишком медленно. Java 8 появилась аж в 2014 году, Java 9 на момент публикации уже вышла, но в самом языке слишком мало новых фишек. Более того, с Java 9 у многих все в момент перестало работать. И тут людям дают язык, наполненный фичами, часть из которых появится только в 10-ке.

Чем этот ваш Kotlin круче?

Авторы языка признаются, что не пытались придумать что-то кардинально новое. Язык специально задумывался максимально прагматичным и удобным в использовании для разработчиков. Вот небольшой список фишек, которые в нём есть:

C более полным списком можно ознакомиться по ссылке.

Как оно помогает жить?

Null safety — это selling point Kotlin. Проверка на nullable type осуществляется еще во время компиляции.

var a: String = "abc"
a = null // compilation error

var b: String? = "abc"
b = null // ok

Это очень удобно и помогает избежать многих багов.

Extension functions — это фича, которой разработчикам часто очень не хватает в Java. Ниже пример, как с помощью всего пары функций можно улучшить существующий Selenium API

fun WebDriver.open(url: String) {
    get(url)
}

fun WebDriver.all(cssselector: String): MutableList<WebElement>? {
    return findElements(By.cssSelector(cssselector))
}

fun List<WebElement>.shouldHave(size: Int) {
    assert(this.size == size)
}

По итогу можно писать тесты в таком формате:

val driver = ChromeDriver()
driver.open("http://automation-remarks.com")
driver.all(".post").shouldHave(size = 9)

Еще одной фишкой являются функции типа .apply.with. C их применением можно сделать код более компактным.

ChromeDriver().apply {
        open("http://automation-remarks.com")
        all(".post").shouldHave(size = 9)
}

String template — позволяет форматировать строки, что удобно использовать в тестах.

fun findCustomerById(id:Long): CustomerEntity{

    val query = """
                SELECT *
                FROM customer
                WHERE id = $id;
                """

    return findOne(CustomerEntity::klass, query)
}

Как видите, SQL запрос не содержит уродливых переносов строк и конкатенаций. Его просто читать, копировать и редактировать.

Reified type — фишка, которая позволяет сделать ваш код очень красивым и лаконичным. Например, с применением библиотеки Apache DBUtils код получается таким:

val beanHandler = BeanHandler<City>(City::class.java)
val city: City  = QueryRunner().query("SELECT * FROM city", beanHandler)

Но, применив уже знакомые нам extension function и reified type, мы можем сделать так:

inline fun <reified T> QueryRunner.findOne(sql: String): T {
    return BeanHandler(T::class.java).run { query(sql, this) }
}

и получить следующий код:

val city : City = QueryRunner().findOne("SELECT * FROM city")

В этом случае тип, в который конвертируется результат запроса, будет браться из типа объявленной переменной. Это гораздо удобнее, чем Java Generics.

Совместимость с Java

Из официальной документации известно, что Kotlin разрабатывался с оглядкой на максимальную совместимость с Java. Java Interop подается под соусом, что мы можем взять любой код, написанный раньше, и вызвать в Kotlin. Либо же обратно — няшный Kotlin-код вызвать в унылой джавке.

Так ли это на самом деле? Давайте разбираться.

Kotlin vs Rest Assured

Посмотрим, как библиотека — Rest Assured будет работать в Kotlin.

Так так, when зарезервированное слово. Обойти такое ограничение можно, обернув его в такие вот интересные кавычки, которые сложно с первого раза найти на клавиатуре.

Kotlin + Selenide

Для написания UI тестов удобно использовать Selenide. Давайте посмотрим на совместимость.

И снова неудача — $ нельзя, val тоже нельзя.

Kotlin + Hamcrest (AssertJ)

Все мы при написании тестов активно используем такие библиотеки, как Hamcrest и AssertJ. Что с совместимостью?

Здесь нас тоже ждут ограничения.

Все через костыли

Когда начинаешь натыкаться на такие ограничения, то напрашивается вполне логичная мысль...

Чиним Kotlin и Rest Assured

На самом деле все предыдущие примеры можно в какой-то степени починить. Смотрим на пример с Rest Assured:

fun RequestSpecification.When(): RequestSpecification {
        return this.`when`()
}

@Test
fun basicPingTest() {
   given()
      .When()
      .get("/garage")
      .then().statusCode(200);
}

Делаем extension function, в который оборачиваем вызов when. Работает? Работает. Да, это костыль, но рабочий.

Чиним Kotlin vs Selenide

В случае с Selenide нам нужно просто обернуть вызовы функций $ и $$, a вместо .val() вызывать .setValue().

fun get(selector: String) : SelenideElement {
     return `$`(selector);
 }
    
 fun all(selector: String) : ElementsCollection {
     return `$$`(selector);
 }

Результат:

@Test fun usingDollarsWithBackticks() {
        get(By.name("q")).setValue("selenide")
        all("#ires .g").shouldHave(size(10))
        get("#ires .g").shouldHave(text("Kotlin"));
 }

Чиним Kotlin + Hamcrest (AssertJ)

Увы, по этому пункту нас ждет разочарование. Если Hamcrest еще как-то совместим с Kotlin, то AssertJ починить не получится из-за несовместимости в Generic types. Здесь нам нужно просто взять и заменить библиотеку. Благо, на GitHub уже есть энтузиасты, которые написали порт — assertk.

@Test fun example(){
    assertThat(1).isEqualTo(1)
}

assert {
    throw Exception("error")
}.throwsError {
    it.hasMessage("wrong")
}
// -> expected [message] to be:<["wrong"]> 
                         but was:<["error"]>

Следует отметить, что assertk обладает более удобным API и полностью совместима с Kotlin.

Вроде бы все наши проблемы мы «подлечили», ну или хотя бы подставили костыли. Естественно, вы можете не натолкнуться на трудности, приведенные выше, если на старте проекта будете выбирать библиотеки и технологии, совместимые с Kotlin.

Чем же все-таки хорош Kotlin?

В дополнение к языковым фичам и синтаксическим конструкциям, можно отметить, что язык очень лаконичный и позволяет строить удобные DSL. В подтверждение ниже показан пример теста, написанного с применением библиотеки Kirk, которая призвана заменить Selenide для Kotlin.

Пример четко демонстрирует, какого формата DSL можно писать. По сути — это BDD, только в коде, со всеми плюшками в виде строгой типизации, автодополнениями и поддержкой рефакторинга.

Что имеем в итоге?

Kotlin — очень приятный язык. Все, что уже реализовано у конкурентов Java, в нем есть. Конвертировать существующий код на Java в Kotlin немного проблематично. Нет еще пока полной совместимости со всеми самыми популярными Java-фреймворками и библиотеками. Выбирать Kotlin или хейтить его и идти учить JS — это Ваше решение. Но вы просто можете перейти по ссылочке на свежий репорт от Rebel Labs о состоянии Java-экосистемы, в котором Kotlin назван самым любимым языком c коэффициентом удовлетворенности 9.1 из 10.

Материалы взяты из статьи Сергея Пирогова.

Похожие материалы:

Зачем учить язык Go?

Комментарии

ВАКАНСИИ

Добавить вакансию
Разработчик C++
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ