Kotlin – kalkulator część trzecia – testy jednostkowe

Testy jednostkowe Kotlin? Groovy?

W tym poście opiszę jak stworzyć testy jednostkowe do napisanego wcześniej kalkulatora. Testy to bardzo ważna część pisania oprogramowania. Są różne podejścia między innymi TDD czyli test-driven-development. W sytuacji idealnej testy powstają przed napisaniem właściwego kodu! Tak, testujemy kod którego jeszcze nie ma. Oczywiście taki test ma się nie udać. Wtedy wracamy do implementacji testowanej metody. I jak poszło wszystko dobrze test powinnien się udać. Robimy refactor a testy już utrzymują za nas czy wiedzę czy to działa! To mega ważne przy dużych projektach.

Stwórzmy nowy projekt

Będzie łatwiej zarządzać zależnościami niż wpadać w tak zwane dependency hell. Oczywiście w tym wypadku dałoby się to zrobić ręcznie ale przygotowujmy się do porządnej roboty i dbania o czystość. Tak więc zakładamy nowy projekt w intellij idea, Wybieramy Gradle,Build new project  zaznaczamy Kotlin i Groovy.  Wybieramy nazwę,  zaznaczamy opcję auto-importu po włączeniu się okna projektu powinniśmy zastać mniej więcej taką strukturę:
structure
Dodałem już klasę mainTest.groovy, oraz potrzebne zależności w pliku build.gradle

testCompile ('org.spockframework:spock-core:1.0-groovy-2.4',
            group: 'junit', name: 'junit', version: '4.12')

Czyli bibliotekę spock do testowania. Przekopiujemy cały kalkulator z poprzedniej lekcji i dla lepszego zrozumienia zmienimy tylko funkcje add itd. na prywatne. Całość w linku żeby nie zaśmiecać posta.
Teraz czas wziąć się za właściwą robotę.

Pisanie testów – Groovy, Kotlin

Moduł napisany jest w Kotlinie a testy napisze w groovym bo tak wyglądają jeszcze przejrzyściej. A oba języki działają na JVM, JRE. Czyli dla maszyny wirtualnej nie ma znaczenia czy ja to piszę w Javie, Kotlinie, Groovym, Clojure
Przechodząc do testów, importuje Spocka, oraz swój moduł:

import spock.lang.Specification
import pl.kotliners.calc.MainKt

class MainKtTest extends Specification {...}

Klasa dziedziczy po Specification ze Spock co daje nam możliwość testowania metod prywatnych.
co?
metod prywatnych?
w innym module?
no tak, taka sztuczka, dzięki libce Spock. Czasem warto nagiąć zasady do celów testowania.

Pierwszy test

zacznijmy od dzielenia:

void "division"(){
    given:
    int a = 6
    int b = 2

    when:
    int div = MainKt.division(a, b)

    then:
    div == 3
}

Funkcja o nazwie division. Ma dane inta a i b, następnie liczy div z MainKt.division(a,b) co jest równoważne 6/2 = 3
i sprawdzamy czy wynik jest równy trzy. Nie musimy pisać adnotacji bo spock się orientuje, że to jest test.
Nasza funkcja posiada If’a więc też należy go otestować. Sprawdziliśmy już, że w normalnej sytuacji działa. Tak więc pora na następny test.
Widzimy, że w razie jeśli drugi argument wynosi zero to zwracamy zero. Piszemy następny test

void "division by zero"(){
    given:
    int a = 6
    int b = 0

    when:
    int div = MainKt.division(a, b)

    then:
    div == 0
}

Ok, czas na test pozostałych trzech metod. Powinno pójść szybko wiemy już jak testować.
Zajmijmy się mnożeniem. Zdefiniujmy sobie int a i b w pakiecie nie będziemy musieli pisać “given:” bo wyszczególnione przypadki dzielenia już sprawdziliśmy.

void "multi"(){
    when:
    int multi = MainKt.multiplication(a, b)

    then:
    multi == 6
}

Test nie przechodzi, jak to? A no to taka moja zasadzka.

Condition not satisfied:

multi == 6
| |
5 false

Expected :6

Actual :5

Jeśli przekopiowałeś kod z pastebina to dodałem -1 w funkcji mnożenia. Możemy założyć, że gdzieś podczas codziennej pracy się pomylimy i dlatego właśnie piszemy testy. Teraz z łatwością rozwiązujemy problem bo problem jest w funkcji test jest OK!. I teraz powinno działać.
Dodajemy analogicznie test do dodawania i odejmowania. Postaraj sie zrobić to samemu a ja wkleję cały kod:

import pl.kotliners.calc.MainKt
import spock.lang.Specification

class MainKtTest extends Specification{

    int a = 2
    int b = 3

    void "adding"() {
        when:
        int sum = MainKt.add(a, b)

        then:
        sum == 5
    }
   
    void "subtraction"(){
        when:
        int sub = MainKt.subtraction(a, b)

        then:
        sub == -1
    }

    void "multi"(){
        when:
        int multi = MainKt.multiplication(a, b)

        then:
        multi == 6
    }

    void "division"(){
        given:
        int a = 6
        int b = 2

        when:
        int div = MainKt.division(a, b)

        then:
        div == 3
    }

    void "division by zero"(){
        given:
        int a = 6
        int b = 0

        when:
        int div = MainKt.division(a, b)

        then:
        div == 0
    }
}

Właśnie napisaliśmy nasze pierwsze testy jednostkowe. A naszmym oczom powinien ukazać się ładny napis:

Tests Passed: 5 passed

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *