Kirjautuminen

Haku

Tehtävät

Keskustelu: Yleinen keskustelu: Yksikkötestauksen ongelmat

Sivun loppuun

Davy-Jones [12.04.2023 19:15:34]

#

Olen aloitteleva Javan parissa ja minun pitäisi etsiä kyseisestä luokasta bugeja testi metodeja käyttäen enkä oikein keksi, että miten pääsisin alkuun tai että minkälaisia testejä lähtisin toteuttamaan. Ohessa kyseinen luokka:

public class DayOfYear {

    public static int dayOfYear(int month, int dayOfMonth, int year) {
        if (month == 2) {
            dayOfMonth += 31;
        } else if (month == 3) {
            dayOfMonth += 59;
        } else if (month == 4) {
            dayOfMonth += 90;
        } else if (month == 5) {
            dayOfMonth += 31 + 28 + 31 + 30;
        } else if (month == 6) {
            dayOfMonth += 31 + 28 + 31 + 30 + 31;
        } else if (month == 7) {
            dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30;
        } else if (month == 8) {
            dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30 + 31;
        } else if (month == 9) {
            dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31;
        } else if (month == 10) {
            dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30;
        } else if (month == 11) {
            dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31;
        } else if (month == 12) {
            dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 31;
        }

        return dayOfMonth;
    }
}

Teuro [12.04.2023 20:07:21]

#

Voisi olla fiksua ainakin ensin määritellä millainen on odotettu tulos, kun testi onnistuu ja millainen kun se ei onnistu. Alla yksi vaihtoehto parilla kutsulla. Nämä tietysti kannattaa automatisoida, mutta alkuun pääsemiseksi.

System.out.println(dayOfYear(2, 29, 2023));
/** Pitäisi tulla virhe, koska 2023 ei ole karkausvuosi **/
System.out.println(dayOfYear(2, 29, 2023));
/** Pitäisi tulostua 60, koska 2024 on karkausvuosi **/

Itse koodissa ei ole paljoa järkeä, koska samaa asiaa toistetaan turhaan. Alla esimerkki, miten tätä voisi ainakin vähän parantaa.

public class Main {
    public static int isLeapYear(int year) {
        if (year % 4 == 0) {
            if (year % 100 == 0) {
                if (year % 400 == 0) {
                    return 1;
                } else {
                    return 0;
                }
            } else {
               return 1;
            }
        } else {
            return 0;
        }
    }

    public static int dayOfYear(int month, int dayOfMonth, int year) {
        month -= 1;
        int[] paivat = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

	    if (month >= 1 && isLeapYear(year) > 0) {
	        paivat[1] += 1;
	    }

	    if (dayOfMonth <= paivat[month]) {
    	    for (int i = 0; i < month; ++i) {
	            dayOfMonth += paivat[i];
    	    }
	    } else {
	        return -1;
	    }

	    return dayOfMonth;
	}

	public static void main(String[] args) {
		System.out.println(dayOfYear(2, 29, 2023));
	}
}

Davy-Jones [12.04.2023 20:17:32]

#

Tehtävänannossa pitäisi hyödyntää JUnit-testikirjastoa testaamaan dayOfYear-metodin toimivuutta erilaisilla testitapauksilla. Minulla on vaikeuksia keksiä mitään "testikysymyksiä" tai että miten lähtisin koodin virhetapauksia edes etsimään.

Teuro [12.04.2023 20:42:09]

#

No yhden tuossa jo annoinkin, jossa funtiota kutsutaan tahallaan väärillä arvoilla. Esimerkiksi liian suuren päivämäärä pitäisi aiheuttaa virhe, koska syöte ei ole järkevä. Se miten jokin täsmällinen työkalu toimii, tai miten sitä voi hyödntää selvinnee helposti kurssimateriaalista.

muuskanuikku [13.04.2023 07:21:21]

#

Teuro kirjoitti:

No yhden tuossa jo annoinkin, jossa funtiota kutsutaan tahallaan väärillä arvoilla. Esimerkiksi liian suuren päivämäärä pitäisi aiheuttaa virhe, koska syöte ei ole järkevä.

Kyseenalainen väittämä. Funktion on tarkoitus kertoa, kuinka mones päivä vuoden alusta laskettuna annettu päivämäärä on. Lopputulos ei sinällään muutu siitä, onko päivämäärä kelvollinen kalenteripäivämäärä vai ei.

Ylivuodon salliminen helpottaa useissa tapauksissa kirjaston käyttöä, koska kirjastoon tukeutuvan koodarin ei silloin tarvitse itse tehdä niin paljon tarkistuksia omassa koodissaan. Riippuu ihan kirjaston käyttötarkoituksesta.

Voisi ihan hyvin riittää tarkistaa funktion lopussa, ylittääkö laskettu tulos arvon 365 (366), sillä mikään vuosi ei voi sisältää enempää päiviä.

Ymmärsit myös tehtävänannon väärin. Tarkoitus ei ollut korjata koodia kirjoittamalla se uusiksi, vaan analysoida koodin oikeellisuutta yksikkötestien avulla. Ei ole mitään järkeä antaa kotitehtäväksi testata virheetöntä koodia...

Omakin funktiosi toimii silti väärin, koska -1 ei ole kelvollinen arvo. Heitä poikkeus.

muuskanuikku [13.04.2023 07:42:00]

#

Davy-Jones kirjoitti:

Tehtävänannossa pitäisi hyödyntää JUnit-testikirjastoa testaamaan dayOfYear-metodin toimivuutta erilaisilla testitapauksilla. Minulla on vaikeuksia keksiä mitään "testikysymyksiä" tai että miten lähtisin koodin virhetapauksia edes etsimään.

Onhan teille pakostakin opetettu testaamisen alkeisteoriaa ennen kuin on käsketty lähteä testailemaan?

Ensimmäinen ohje on se, että pitää testata sallitun arvoalueen reunoja. Testaa siis näillä arvoilla:
(1, 1, 2023)
(12, 31, 2023)

Karkausvuoden toki tuntevat kaikki. Testaa siis reunat myös karkausvuotta käyttäen:
(1, 1, 2024)
(12, 31, 2024)

Testaa seuraavaksi epäkelvoilla syötteillä kuten:
(2, 0, 2023)
(12, 32, 2023)
(13, 31, 2023)

Tosin kuten edellisessä viestissä kirjoitin, niin tuo ensimmäinen tapaus ei välttämättä ole epäkelpo syöte. (Tällöin oikea tulos olisi 31.) Riippuu siitä, miten funktion toiminta on speksattu.

Tämän jälkeen testitapauksia voi laatia lisää sen mukaan, kuinka paljon aikaa tai muita resursseja on käytettävissä kyseisen komponentin testaamiseen. Yleensä kaikkia mielivaltaisia skenaarioita ei voida testata, koska raha ja aikataululliset syyt pakottavat siirtymään seuraavaan tehtävään.

Ihan kaikkea ei kannata yrittääkään testata, koska myös testitapauksia on usein korjailtava jälkikäteen kirjaston koodin kehittyessä. Mitä enemmän "turhia" testitapauksia on, sitä enemmän niiden korjaamiseen menee aikaa.

Tässä tapauksessa sallittu arvojoukko on kuukausien osalta aika pieni, minkä lisäksi eri kuukausissa on eri määrä päiviä, joten voisi olla järkevää testata funktion oikeellisuus jokaisen kuukauden kohdalla yksittäin niin karkausvuosina kuin tavallisinakin vuosina. Tällöin riittää testata yhdellä päivämäärällä per kuukausi.

(1, 15, 2023)
(2, 15, 2023)
(3, 15, 2023)
(4, 15, 2023)
(5, 15, 2023)
(6, 15, 2023)
(7, 15, 2023)
(8, 15, 2023)
(9, 15, 2023)
(10, 15, 2023)
(11, 15, 2023)
(12, 15, 2023)

(1, 15, 2024)
(2, 15, 2024)
(3, 15, 2024)
(4, 15, 2024)
(5, 15, 2024)
(6, 15, 2024)
(7, 15, 2024)
(8, 15, 2024)
(9, 15, 2024)
(10, 15, 2024)
(11, 15, 2024)
(12, 15, 2024)

Näitä varten ei tarvitse välttämättä laatia erillisiä testitapauksia jokaiselle kuukaudelle vaan voit testata ne yhdessä testitapauksessa silmukkaa käyttäen, kun syötät odotetut oikeat arvot taulukkoon.

Tällöin on kuitenkin oltava hyvin huolellinen siitä, että testitapaus itsessään toimii oikein. Bugi testitapauksen omassa koodissa voi joskus johtaa siihen, että bugi testattavassa koodissa jää löytämättä. Testitapaukset kannattaa pitää yksinkertaisina ja välttää kaikkea ihmeellistä kikkailua.

Davy-Jones [13.04.2023 12:57:17]

#

Huomasin ainakin sen, että ohjelma olettaa että jokainen vuosi on karkausvuosi.

esim:

public void karkausVuosiTesti() {

		int tulos = DayOfYear.dayOfYear(12, 31, 2023);

		assertEquals(365, tulos);

tuloksen pitäisi olla 365, mutta ohjelma sanoo että "oikea" vastaus on 366.

muuskanuikku [13.04.2023 14:57:10]

#

Kannattaa raaputtaa kaikki testitapaukset ensin ja miettiä sitten syitä virheellisiin tuloksiin.

Jos luet tuota koodia ajatuksella, niin huomaat varmaan sen, ettei karkausvuotta huomioida itse asiassa ollenkaan. Syy väärään tulokseen on toisessa virheessä...

Älä nyt kuitenkaan ensin etsi kaikkia alkuperäisen koodin virheitä silmämääräisesti, jotta osaisit laatia "oikeat" testitapaukset. Silloin tehtävänannon todellinen tarkoitus menee hukkaan.

Davy-Jones [13.04.2023 15:21:39]

#

Tämä on varmaan väärin, mutta omasta mielestäni tuntuu oudolta tai en oikein ymmärrä että miksi läpikäydessä ensimmäinen kohta on tuo : if (month == 2). Näin aloittelijan silmään tuntuu oudolta, tosin voin olla väärässä.

Davy-Jones [13.04.2023 15:30:37]

#

Tehtävänannossa myös sanotaan, että "Kukin testitapaus, eli testimetodi, voi käytännössä koostua vain kahdesta rivistä. Ensimmäisellä rivillä kutsut testattavaa dayOfYear-metodia, ja toisella rivillä tarkistat, onko metodista saatu tulos on oikea." Ymmärrän tämän esim vaikkapa tuo: public void karkausVuosiTesti() {
int tulos = DayOfYear.dayOfYear(12, 31, 2023);
assertEquals(365, tulos);

Ongelma tulee siinä, että en oikein keksi mitään "fiksuja" testejä, millä metodia testata.

muuskanuikku [13.04.2023 15:51:39]

#

Davy-Jones kirjoitti:

Tämä on varmaan väärin, mutta omasta mielestäni tuntuu oudolta tai en oikein ymmärrä että miksi läpikäydessä ensimmäinen kohta on tuo : if (month == 2). Näin aloittelijan silmään tuntuu oudolta, tosin voin olla väärässä.

Tämähän on tehtävänantoa ajatellen erinomainen asia. Blackbox-testaamisessa funktion toteutusta ei kuulukaan tietää / ymmärtää. Sinun on sen sijaan laadittava testitapaukset itsenäisesti perustuen siihen, miten funktiota pitäisi voida speksin mukaan käyttää.

muuskanuikku [13.04.2023 15:51:57]

#

Davy-Jones kirjoitti:

Ongelma tulee siinä, että en oikein keksi mitään "fiksuja" testejä, millä metodia testata.

Juurihan minä annoin sinulle noin 30 erilaista testitapausta...

Davy-Jones [13.04.2023 18:36:16]

#

Taisin valita väärän alan itselleni mitä opiskella. Kokeilin erilaisia testitapauksia, mutta en oikein siltikään ymmärrä että miten ne auttavat tehtävässä etenemissessä. Esimerkiksi jos testaan vaikkapa vuoden viimeistä päivää tavallisena vuonna:

public void karkausVuosiTesti() {

int tulos = DayOfYear.dayOfYear(12, 31, 2023);

assertEquals(365, tulos)}

niin saan tulokseksi virheen, koska "odotettu" vastaus on 366.

muuskanuikku [13.04.2023 19:11:16]

#

No mikä testitapauksen tuloksen sitten mielestäsi pitäisi olla? Jos funktio toimii väärin eli palauttaa väärän tuloksen, niin testitapauksen tuleekin ilmoittaa virheestä.

Tämän viestiketjun avausviestissä kerroit tehtävänä olevan etsiä bugeja yksikkötestien avulla. Löysit bugin. Nyt ihmettelet, että mitä sinun pitikään tehdä?

Davy-Jones [13.04.2023 19:24:35]

#

Testitapauksen tulos pitäisi tuossa mielestäni olla 365, koska vuosi 2023 ei ole karkausvuosi, tarkoitan siis että testitapauksen ei pitäisi tuossa kyseisessä esimerkissä ilmoittaa virheestä.

muuskanuikku [13.04.2023 19:25:24]

#

Davy-Jones kirjoitti:

Testitapauksen tulos pitäisi tuossa mielestäni olla 365, koska vuosi 2023 ei ole karkausvuosi

Ja mitä sitten?

"Testitapauksen" tulos on aina joko "testi onnistui" tai "testi epäonnistui".

Davy-Jones [13.04.2023 19:29:20]

#

muuskanuikku kirjoitti:

"Testitapauksen" tulos on aina joko "testi onnistui" tai "testi epäonnistui".

Ymmärrän tämän, eli nytten sitten pitäisi varmaan lähteä koodia korjaamaan. Tehtävän toisessa osassa tarkoituksena on korjata dayOfYear-luokan bugit.

muuskanuikku [13.04.2023 19:30:42]

#

Laadi nyt ensin kaikki tarvittavat testitapaukset.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta