ComTest ja Ohjelmointi 2 -kurssi

# asennusurakka

Asennusurakka

# asennusedistyy20
# asennusongelma20

ComTest on lähtöisin alun perin Vesa Lappalaisen ideasta, että yksikkötestauksen pitäisi olla mahdollisimman helppoa ja vaivatonta. Projekti on tällä hetkellä siinä vaiheessa, että Eclipse Pluginilla voidaan luoda ja ajaa kohtuullisella vaivalla testejä. Eclipse ei kuitenkaan tällä hetkellä ymmärrä testien syntaksia ja tämä hieman vaikeuttaa testien kirjoittamista. Ennen pluginin suurempaa hiomista pitää kuitenkin varmistaa perusajatuksen toimivuus.

Tärkeää ComTestissä on yksikkötestaamisen lisäksi se, että siitä saa myös hyvän dokumentaation metodien toiminnasta (ks. Mjonot-dokumentaatio). Lisäksi helppokäyttöisten testien avulla voi mukavasti määritellä itselleen esimerkiksi metodin rajapinnan.

ComTest on "vain" makrokieli, jolla kirjoitetut testit "käännetään" Javan normaaliksi JUnit-testitiedostoksi. Alempana on taulukkomuotoisen testaamisen yhteydessä esimerkkejä, joista voi katsoa minkälaiseksi JUnit-tiedostoksi ComTest-testi kääntyy.

Mjonot -linkki sanoo 404

VL: Vaihdoin linkin uudempaan.

09 Jan 24 (edited 10 Jan 24)

Lisenssiasiaa: jos projektin haluaa julkaista omalla nimellään ja siellä on käyteytty ComTestiä tai muita kirjastoja, ja ylipäätään projektia on tehty tällä kurssilla, miten laki- ja lisenssiasiat menee? Käsittääkseni itse tehty työ on täälläkin aina oma ja kurssin erikoisemmat työkalut kuten comtest lienevät MIT-lisenssin alla. Jos lopulta ohjelmasta tulee vaikka maksullinen, tuleeko mitään ongelmia? Omistanhan täysin itse projektin jota on tehty tällä kurssilla?

VL: Vaikka sitä ei ole nähtävästi mihinkään erikseen kirjoitettu, niin ainakin mun juttujen oletetaan olevan MIT-lisenssillä (kuten TIM), eli saa käyttää. Toki omanaan myyminen on epäreilua jos ei ole merkittävää omaa kontribuutiota. ELi oman projektisi omistat ja saat käyttää kurssin materiaaleja/aliohjelmia sen toteuttamiseksi.

3 days ago (edited 3 days ago)

1. Käyttöesimerkki

# V1
# koti

2. Asentaminen kotikoneeseen (Eclipse)

Win:   c:\devel\ec2312\eclipse\dropins
Mac:   /Applications/Eclipse.app/Contents/Eclipse/dropins
Linux: /home/Anonymous/devel/ec2312/Eclipse/dropins

dropins-kansioon tallentaminen Mac:issä:

  • Ilman mitään asentamista, voit kokeilla ComTestin toimintaa Copy/Pasteamalla koko testattava ohjelma (luokka) TIM-oppimisympäristön ComTest-pohjaan.

2.1 Mistä tiedän että toimii?

  1. Tee uusi Eclipse Java-luokka (jos ei ole projektia, niin tee ensin uusi projekti):

    1. File/New/Class
    2. Package: example
    3. Name: Laskuja
    4. Finish
  2. Kopioi tiedoston Laskuja sisällöksi:

    package example;
    /** Kokeillaan testejä */
    public class Laskuja {
       /**
        * @param a eka summattava 
        * @param b toka summattava
        * @return a+b
        * @example
        * <pre name="test">
        *   summa(2,3) === 5;
        *   summa(-5,5) === 0;
        *  </pre>
        */
       public static int summa(int a, int b) {
           return a + b;
       }
    
       /** @param args ei käytössä */
       public static void main(String[] args) {
           System.out.println("Summa = " + summa(3,2));
       }
    }
  3. Lisää projektiin Junit 5:

    1. Paina projektin nimen päällä hiiren oikealla
    2. Valite Properties
    3. Java Build Path/Libraries
    4. Klikkaa Classpath (jos Classpath ei ole valmiiksi näkyvissä, klikkaa ensin Libraries.)
    5. Add Library...
    6. Junit
    7. Next
    8. JUnit 5
    9. Finish
    10. Apply and Close
  4. Valitse tiedosto Laskuja.java, sitten hiiren oikealla ComTest/Generate, Run Junit

  5. Pitäisi tulla vihreää.

  6. Siirrä testi-ikkuna alalaitaan Console-ikkunan kaveriksi

  7. Poista syntynyt testitiedosto LaskujaTest.java

  8. Lisää alempana olevan ohjeen mukaan comtest.ini esim omaan ohj2-kansioosi niin jatkossa testit tulevat omaan hakemistoonsa.

  9. Kokeile vielä tämän jälkeen ajaa testit uudelleen Laskuja-tiedostolle.

  10. Jos Qtrl-Q ei toimi, niin:

    1. Window/Preferences
    2. kirjoita hakusanaksi keys
    3. Klikkaa Keys
    4. Kirjoita Scheme alapuolella olevaan hakusana-kohtaan Last edit tai Previous edit location
    5. Jos Ctrl-Q on yhdistetty tähän, niin mene kohtaan Binding ja tyhjennä se.
    6. Paina Apply.
    7. Kirjoita vielä hakusanaksi comtest ja katso onko sillä Ctrl-Q ja When:-kohdassa Editing Text
    8. Muista että aina ennen uutta testiä pitää tallentaa (Ctrl-S)

Miksi antaa comtestistä “This chosen operation is not currently available”?

VL: toistaiseksi kaikilla joilla on ollut tuo vika, on ollut useita Javoja koneessa ja Eclipse käyttää oletuksena jotakin vanhaa. Helpoin tapa on poistaa kaikki Javat ja sitten tehdä JDK 13 asennus uudelleen niin, että on vain yksi Java.

Tuolta löytyi ohje miten saa Eclipsen käyttämään oikeaa jdk:ta. Laitoin myös ohjeen virhesivulle, ainakin itsellä korjautui. - pyjuella

07 Jan 20 (edited 30 Dec 20)

ComTest: Saan ilmoituksen “No JUnit tests found” ja en saa ratkaistua ongelmaa, miksi ei toimi. Junit5 on laitettu eclipseen.

VL: Tuo tulee silloin kun testattavassa ohjelmassa ei ole ComTestin vaatimia otiskoita kuten example ja pre. Voinee tulla myös jos ComTest.jar ei löydy tai Javaa ei voi ajaa?

11 Jan 21 (edited 11 Jan 21)

Itsellä ei ComTestit toiminut kun lisäsin Junit 5 kirjaston. Kun lisäsin kirjastoon myös Junit 4 & 3 niin sain ohjeissa olevan Comtest/Generate, Run Junit vaihtoehdon. Jos muilla vastaava ongelma niin suosittelen testaamaan.

27 May 21 (edited 27 May 21)

ilmoitus: no JUnit test found kohdan 4 jälkeen…

HL: Kohdassa 3 lisätään projektiin Junit 5.

14 Sep 21 (edited 15 Sep 21)

Minullakin tulee, että "no junit tests found". Siihen alle kyllä tulee kaksi uusi haara "example test" ja sen alle LaskujaTest.java. Mainittakoon vielä ylemmästä HL:n ohjeesta, että JUnit 5 on lisätty. :SOLVED

VL: Liatatko vielä mikä oli vika jos muilla on samaa?

09 Jan 24 (edited 10 Jan 24)
  1. Kokeile vielä että ComTest-pohjan teko onnistuu (unohtui videolla):
    1. Tee kommentin sisällä (eli /** ja */ välissä) vaikka juuri ennen loppumerkkiä uusi rivi.
    2. Kirjoita tähden perään (ei kiinni tähteen, vaan ainakin yksi välilyönti) comt ja paina Ctrl-Space (eli Ctrl ja välilyönti).
    3. Pitäisi ilmestyä runko ComTestin kirjoittamiselle. Tosin tuonne on ilmestynyt valtava määrä muitakin ko lyhenteellä tulevia ja ComTest on niiden viimeisenä. Se löytyy nopeasti, kun painaisee nuoli ylös. Itse asiassa riittää: c Ctrl+väli nuoli ylös
    4. Jos haluat valtavan listan karsia pois, niin mene valikossa kohtaan Window -> Preferences -> Java -> Editor -> Content Assist -> Advanced ja sieltä ylemmästä laatikosta (Select the proposal kinds contained in the 'default' content assist list) ota ruksi pois kohdasta Java proposals ja paina Apply.

Hätätilassa lue tarkemmin ComTestin asennusohjeesta.

Nyt saat ruksia asennetuksi kohdan: ComTest.

3. Asentaminen mikroluokassa

  1. Tarkista ensin toimiiko ComTest: Java tiedoston päällä paina hiiren oikeata nappia
  2. Jos ComTest näkyy, niin asia on kunnossa.
  1. Jos ComTest ei näy, niin toimi seuraavasti
  Eclipse 3.4 ja uudemmat
   - siirry komentoriville
   - kirjoita alustacomtest  (jos n-levy ei ole käytössä, aktivoi se työpöydältä)

4. Ongelmatapauksissa

  • Ongelmatapauksissa katso ensin: ComTestin ongelmia-kohdasta
  • Mainittu Eclipsen configuraatiohakemiston on mikroluokissa u:\config\eclipse (eli jos tulee suuria ongelmia, sammuta Eclipse, poista tämä hakemisto, käynnistä Eclipse uudelleen)

5. Peruskäyttö

  • Testien hyvän toiminnan kannalta Java-tiedostot kannattaa kirjoittaa paketteihin (ei default package, aloita siis aina luomalla src-hakemiston alle työtäsi kuvaava paketti)

  • ÄLÄ käytä tiedostojen ja pakettien yms. nimissä SKANDEJA (ä,ö,å). Tulee siis ongelmia jos pakettisi nimi on tehtäviä, vaihda siis tällaiset nimet muotoon tehtavia

  • Nykyään tämä tehdään automaattisesti. Jos haluat testien menevän eri hakemistoon kuin itse Java-tiedostojen (isoissa projekteissa tapana), kirjoita jollakin tekstieditorilla tiedosto ComTest.ini. Sijoita se sinne hakemistoon, missä on testatta Java-tiedostosi tai johonkin sen yläpuoliseen hakemistoon. Tiedoston ComTest.ini jonka sisältö on oletusarvoisesti:

    #BEFORETESTCLASS= @SuppressWarnings("all")
    #DIRECTORY=test
    #PACKAGE=.test

Miten ComTest.ini tehdään? Itse kekkaloin sellaisen Notepadilla. Niinkö? Miten sen saa näkymään/kuuluuko sen näkyä Eclipsen Package Explorerissa?

VL: se on tekstitiedosto ja se on ihan sama millä (!= Word) sen kirjoittaa. Ja se näkyy normalisti hakemistossa, Eclipsessä sen ei tarvitse näkyä. Kun ComTest ajetaan, se kiipeää nykyhakemistosta ylöspäin kunnes tuo löytyy ja käyttää siinä olevia asetuksia. Eli sen voi sijoittaa niin ylös hakemistopuussa, ettei Eclipse siitä mitään edes tiedä.

10 Jan 19 (edited 30 Dec 20)

Mitä Java-tiedostolla tässä tarkoitetaan? Sitä paikkaa, johon jdk-15…-hakemisto on sijoitettu?

VL: ei, tarkensin tekstiä.

30 Dec 20 (edited 30 Dec 20)
  • Mene sen aliohjelman JavaDoc kommentteihin, jota haluat testata

  • Tee loppuun yksi tyhjä rivi (siis sellainen jossa on * alussa)

  • Kirjoita comtest ja paina Ctrl-Space (katso CtrlSpaceEiToimi). Jos tulee paljon valintoja, niin valitse ComTest Example

  • Sinulle pitäisi tulla tyhjä "raami":

        * @example
        * <pre name="test">
        * 
        * </pre>
  • Tähän raamiin kirjoitetaan testi. Esimerkiksi:

        * @example
        * <pre name="test">
        *   poista("Catcat"   ,"at")  ===  "Cc";
        *   poista("Paatti"   ,"at")  ===  "Pi";
        *   poista("Puatit"   ,"at")  ===  "Puit";
        * </pre>
  • Voi käyttää myös tarvittaessa esim: #import fi.jyu.mit.ohj2.*;

  • Tallenna työsi ennen testien generoimista ja ajamista.

  • Muista lisätä JUnit 5 projektiisi (menusta: Project/Properties/Java Build Path/Add Library/JUnit/JUnit 5/Finish )

  • Paina hiiren oikeata nappia ja valitse ComTest/Generate, Run JUnit

  • Jos tulee käännösvirheitä, avaa syntynyt testi-ohjelma ja koeta keksiä virheen syy.

  • Jos tulee ajossa ilmoitus väärästä tuloksesta, niin mieti onko väärin testi vai toteutus. Korjaa.

  • Jos testi on sisennetty, JUnit ei välttämättä osaa poistaa sisennystä, vaan etsii esim aliohjelmaa " hypotenuusa()".

Minulle ei tule mitään ehdotuksia kun kirjoitan comtest ja painan ctrl + space

KR: Sun pitää olla metodikommentin sisässä:

/** Huom. tässä pitää olla kaksi tähteä.
* comtest
*/
16 Jan 18 (edited 31 Jan 18)

Jos aliohjelma palauttaa boolean arvon niin mitenkäs tämä sitten menne?

KR: Booleaneille vastaavasti esim. palautaTosi() === true;

27 Jan 18 (edited 30 Dec 20)

Mistä johtuu että joskus args punainen viiva häviää kun kommentoidaan, joskus myös ei käytössä saa punaisen viivan ja sille ehdotetaan että lisää sanakirjaan.
VL: katso oikoluvun asetukset ja ota oikoluku pois päältä. Sitten args pitää kommentoida sillä on väärin esitellä parametrejä kommenteissa ja jättää kertomatta mitä ne ovat.

14 Jan 20 (edited 30 Dec 20)

Mitä tuo ehdotettu #import fi.jyu.mit.ohj2.*; tekee esimerkkikoodissa? Pistin ten package-rivin jälkeen ja otin risuaidan pois ja koodi ei käyttänyt sitä mihinkään

VL: jos käytät tuolla kirjastossa olevia kutsua, pitää se importata

14 Jan 20 (edited 30 Dec 20)

Oliko comtestissä millainen syntaksi jos haluaa testata esimerkiksi että jokin olio != null?

VL: lisäsin olioiden testaamisen kohdalle.

14 Mar 20 (edited 14 Mar 20)

Mikä on JavaDoc kommentti ja mistä sinne pääsee käsiksi Eclipsessä?

VL: Se on tuo mikä alkaa /** ja sen saa kirjoittamalla noin.

30 Dec 20 (edited 30 Dec 20)

Testasin aliohjelmassa Laskuja valmiina olleet testit, tätäkö tässä haettiin?

VL: Siis siihen riittää että työkalu toimii, jatkossa lisää.

30 Dec 20 (edited 30 Dec 20)

6. Kaikkien testien ajaminen kerralla

Harjoitustyön tekemisen yhteydessä kaikkien tiedostojen testaaminen yksitellen voi olla hidasta. Voit ajaa kaikki ComTest-testit kerralla seuraavasti:

  • Valitse Package Explorerista ne tiedostot, jotka haluat testata. Jos esim. haluat testata jonkun paketin kaikki tiedostot, niin klikkaa paketin ylimmäistä tiedostoa, Shift pohjaan ja klikkaa alimmaista tiedostoa.
  • Klikkaa hiiren oikeaa ja ComTest -> Generate tests.
  • Valitse generoidut testitiedostot (yleensä riittää valita paketti, jossa ne sijaitsevat) ja klikkaa hiiren oikeaa -> Run As -> JUnit Test.
# doublecompare

7. Hieman edistyneempi käyttö

  • Reaalilukuja testataan seuraavasti:

        * @example
        * <pre name="test">
        * #TOLERANCE=0.01    // Määrää vertailun tarkkuuden (huom ei välilyöntejä)
        * hypotenuusa(0,0) ~~~ 0.0;
        * hypotenuusa(0,1) ~~~ 1.0;
        * hypotenuusa(1,1) ~~~ 1.41;
        * hypotenuusa(1,2) ~~~ 2.24;
        * hypotenuusa(5,6) ~~~ 7.81;
        * </pre>
  • Totuusarvoja testataan seuraavasti:

        * @example
        * <pre name="test">
        * onkoIsolla("KISSA") === true;
        * onkoIsolla("Kissa") === false;
        * </pre>
  • Jos halutaan merkkijonoista "epämääräisyyksiä", käytetään Regular Expressionia:

        * @example
        * <pre name="test">
        * Henkilo2 hlo = new Henkilo2("Aku","Ankka",1934);
        * hlo.toString() =R= "Aku.*";   // Ensin pitää lukea Aku ja 
        •                               // sitten saa olla mitä kirjainta (.) tahansa 
        * </pre>                        // kuinka monta tahansa (*)
  • Muista että RegExpin kanssa voi joutua laittamaan kenoviivoja useampia, jotta ne saa menemään "mätserille" saakka. Esimerkiksi:

        * @example
        * <pre name="test">
        * "kissa\n" =R= "kissa\\s";  // \s olisi reg.expin "tyhjä merkki", 
        * </pre>                     // mutta Java syö \:n pois joten tarvii olla \\

    Tällöin on muistettava että RegExpin omat merkit tuovat oman haasteensa. Eli jos halutaan testata RegExpin avulla samaa kuin:

        vali.toString() === "(3.0-4.0)";

    pitää tämä kirjoittaa

        vali.toString() =R= "\\(3\\.0-4\\.0\\)";

    koska sulkumerkit ovat RegExpin merkkejä ja ne pitää siis "prefixata". Samoin pisteen kohdalla.

    • Jos halutaan testata niin, että desimaalimerkiksi tulee kumpia tahansa (piste tai pilkku) voidaan siinä käyttää tietysti lueteltua joukkoa:

       vali.toString() =R= "\\(3[.,]0-4[.,]0\\)";
    • Lisäksi merkkijonoihin laitetuissa desimaaliluvuissa desimaalien määrä tuottaa aina oman haasteensa.

  • Lue "käyttöohjeita": http://www.mit.jyu.fi/vesal/kurssit/ohj2/comtest/

Onko näin, että tuo #TOLERANCE ei toimi jos sen kirjoittaa "#TOLERANCE = 0.01"? , vaan se pitää kirjoittaa aina kaikki yhteen "#TOLERANCE=0.01".

VL: joo, noi voi olla aika tiukkoja syntaksista (ehkä tarpeettomastikin)

23 Mar 23 (edited 23 Mar 23)
  • StringBuilderin tapauksessa pitää tulos muuttaa ensin merkkijonoksi:

       * StringBuilder sb = new StringBuilder("Aku Ankka");
       * vaihdaEtuJaSuku(sb);
       * sb.toString() === "Ankka Aku";
# shouldthrow

8. Testataan heittääkö poikkeuksen

Usein funktion pitää heittää poikkeus jos jotakin pahaa tapahtuu. Testataan seuraavassa tuleeko koodista indeksin ylityspoikeus:

 *    String jono = "Kissa";
 *    jono.charAt(12) === 'a';  #THROWS IndexOutOfBoundsException

Mikäli poikeusta ei heitetä, aiheuttaa tämä testin epäonnistumisen.

# arraytest

9. Taulukoiden testaaminen

Esimerkki taulukon sisällön testaamisesta

	/**
	 * Käännetään taulukon alkiot päinvastaiseen järjestykseen
	 * @param t taulukko jonka alkiot käännetään
	 * @example
	 * <pre name="test">
	 * #import java.util.Arrays;
	 *    int[] t = {2, 32, 76, 62, 31, 86};
	 *    kaanna(t); 
	 *    Arrays.toString(t) === "[86, 31, 62, 76, 32, 2]";
	 * </pre>
	 */

Onnistuuko kokonaisen String[] taulukon testaaminen jotenkin helposti? Ainakaan toString() avulla en saanut toimimaan.Eli esim. String [] t = {"a","b"}; Arrays.toString(t) === "[a, b]";

VL: Minusta toimii, tein tuohon alemmaksi esimerkin. Se vaan tarvitsee tuon importin

27 Jan 23 (edited 27 Jan 23)

Esimerkki taulukon luomisesta kutsussa:

	/**
	 * Lasketaan yhteen taulukon kaikki luvut
	 * @param t taulukko jonka luvut lasketaan 
	 * @return lukujen summa
	 * @example
	 * <pre name="test">
	 *   int[] t = {1,2,3,4,5,6};
	 *   summa(t) === 21;
	 *   summa(new int[]{1,1,1,1,1,1}) === 6;
	 * </pre>
	 */

Oliko tähän jotain ratkaisua ilmoilla? Mulla on sama ongelma, eli tuo metodi on tuntematon sitten kun se yrittää junitteja ajaa. Syntaksit ja näkyvyydet kokeiltu kymmeneen kertaan.

VL: joku timiin tallennettu koodiesimerkki tarvitaan.

Vastataas nyt pienen väännön jälkeen havaintoja:

Eli olen tehnyt demokerrat omiin projekteihinsa ja nyt unohtui tehdä projektille oma paketti. Java tiedostot meni johonkin default packageen ja siitä kohtaa loppui comtestin ymmärrys. Eli homma rupesi rokkaamaan kun teki oman paketin ja laittoi comtestattavat tiedostot sinne. Tässä tapauksessa comtest osasi luoda paketinNimi.test paketin johon junit-tiedosto meni. Näkyvyysongelmaltahan tuo alunperinkin vaikutti kun junitti ihmetteli että tämmönen metodi on undefined.

VL: Joo, se on jossakin sanottu että ComTest ei toimi jos ei ole pakettia koska ilman pakettia ei voi viitata vieraaseen aliohjelmaan.

24 Feb 21 (edited 03 Mar 21)

Huom! Kutsuun kirjoitettu 2-ulotteisen taulukkon luominen ei toistaiseksi toimi. 2-ulotteiset taulukot pitää toistaiseksi luoda apumuuttujaan.

# arrayst
# objecttest

10. Olioiden testaaminen

Olioita testataan niin, että luodaan testattava olio, tehdään sille jotakin mitä testin luonteen takia tarvitsee ja sitten tavalla tai toisella katsotaan että olion tila vastaa sen jälkeen toivottua tilaa. Usein joku toString tai get-metodi auttaa tilan tarkistamisessa.

# oliot_aika_olio_Aika_java
# shell1

Jos haluaa testata onko olioviite eri kuin null, pitää vähän soveltaa ja testata:

a == null === false;  // tai
a != null === true;
# tabletest

11. Taulukkomuotoinen testaaminen

  • Opettele myös taulukkomuotoinen testaaminen, se vähentää monesti kirjoittamista.

  • Esimerkki kurssin Ali-paketista kun testataan staattista tayta funktiota:

        * @example
        * <pre name="testTayta">
        * tayta($jono,$n) === $tulos;
        * 
        *    $jono   | $n | $tulos
        *  -------------------------------
        *    "kissa" |  3 | "kissakissakissa"
        *    ""      | 10 | ""
        *    "kissa" |  0 | ""     
        *    "kissa" |  1 | "kissa"
        *    "a"     | 10 | "aaaaaaaaaa"     
        * </pre>
  • Lyhyesti: dollarimerkki ($) merkitsee muuttujia, viivamerkit (-----..) ovat koristeita, putkimerkit (|) erottelevat muuttujia ja niiden arvoja.

  • Huomaa että tolpan (|) ympärillä on oltava aina tyhjää, jotta osataan tulkita taulukkomuotoiseksi testiksi. Muuten tästä ei generoidu testejä ja aivan vääränlaisetkin rivit saatavat näyttää tuottavan vihreää. Muista AINA kokeilla, että saat myös punaista!

  • Katso lisää esimerkkejä esim: kurssin Ali-paketista ja erityisesti Mjonot.java.

  • Ideana on siis että ensin kirjoitetaan testistä malliesimerkki ja sitten taulukossa kerrotaan mitä arvoja malliin laitetaan kullakin testiesiintymällä. Jokainen testiesiintymä saadaan sijoittamalla taulukosta vastaavan sarakkeen muuttujia mallitestiin.

Taulukkomuotoisessa testaamisessa on oltava huolellinen, ettei sama muuttuja tai olio-muuttuja tule esiteltyä useita kertoja. Tämä voi tehdä esittelemällä muuttujat ensin ja sitten laittamalla tyhjän rivin ja vasta sitten $-merkillä varustettuja rivejä. Silloin tyhjällä rivillä erotettu osa tulee syntyvään JUnit-tiedostoon vain yhden kerran.

# oliot_aika_olio_Aika_java2
# shell2

Edellä esimerkissä on vielä käytetty taulukkomuotoisen testaamisen ominaisuutta, että mikäli taulukossa on --- jossakin sarakkeessa, niin sellaisia lauseita joissa vastaava sarake esiintyy, ei käännetä lopputulokseen.

Eli edellinen olisi sama kuin kirjoitettaisiin:

# oliot_aika_olio_Aika_java21

Siis --- -arvon takia toiseen testijoukoon ei ole tullut

a = new Aika(---,---);

riviä. Vastaavasti viimeiseen testijoukkoon ei ole tullut lausetta

a.lisaa(---);

koska siinäkin olisi käytetty silloin sarkkeessa olevaa --- -jonoa.

Toinen mahdollisuus välttää muuttujien nimien uudelleenesittely on sulkea koko testattava esimerkkiosa aaltosulkuihin. Tällöin joka testiesiintymää varten syntyy uusi muuttuja. Tällöin ei luonnollisesti voi em. esimerkissä käyttää --- -arvoa $h tai $m sarakkeissa, koska muuuttuja a jäisi kokonaan syntymättä siltä testiesiintymältä.

# oliot_aika_olio_Aika_java3
# shell3

Yksi ComTestin "vika" on että kaikki testit menevät samaan JUnitin testifunktioon. Tästä on haittana se, että jos yksikin testi epäonnistuu, niin muita testejä ei enää ajeta.

Tarvittaessa voidaan erikseen pyytää, että muodostetaan kokonaan uusi testi jokaisesta testirivistä jonka edellä on === -jono. Tällöin vaikka ensimmäinen testi epäonnistuisi, muut kuitenkin ajetaan. Kokeile seuraavassa muutella eri testejä oikeaksi ja vääräksi.

# oliot_aika_olio_Aika_java4
# shell4

12. Sisäluokkien testaaminen

Jos esimerkiksi on stattinen sisäluokka luokka Kierros joka on kirjoitettu luokan Makihyppy sisäluokaksi, niin silloin sen metodia voidaan testata esimerkiksi:

public class Makihyppy {
    public static class Kierros {
         ...
         * @example
         * <pre name="test">
         *    var kierros = new Makihyppy.Kierros();
         *    kierros.setPituus(101);
         *    kierros.setTuomari(0, 0);
         *    kierros.setTuomari(1, 20);
         *    kierros.setTuomari(2, 20);
         *    kierros.getPisteet() ~~~ 61.0;
         * </pre>
         */
        public void setPituus(double pit) {
            pituus = pit;
        }
# import

13. Testissä tarvitaan jotakin ulkopuolista luokkaa

Mikäli testitssä tarvitsee importata joku luokka, jota ei valmiina ole. voidan tämä sanoa esimerkiksi:

 * @example
 * <pre name="test">
 * #import java.io.*;
 * ... käytetään tarvittavia luokkia ...
 * </pre>
# outputstream

14. OutputStreamin testaaminen

  • Funktio, jolle viedään parametrina OutputStream. Esimerkiksi:

     public void tulosta(OutputStream os) {
         PrintStream out = new PrintStream(os);
         out.println("Tulostetaan jotain");
     }
  • Tätä kutsutaan

       tulosta(System.out);
  • Testaus voidaan tehdä seuraavasti:

      * <pre name="test">
      * #import java.io.ByteArrayOutputStream;
      * ByteArrayOutputStream outContent = new ByteArrayOutputStream();
      * Henkilo hlo = new Henkilo("Antti","Virtanen", 30);
      * hlo.tulosta(outContent);
      * outContent.toString() === "Antti Virtanen, 30v\r\n"; // Varoitus: Kaikissa järjestelemissä ei ole sama rivin loppu!
  • Huom! outContent.toString antaa myös rivinerotinmerkin, kun siihen on ne tulostettu. Vertaillessa ne pistää poistaa tai lisätään vertailutekstiin kuten yllä.

  • \r\n sijaan olisi hyvä käyttää System.getProperty("line.separator")-kutsun antamaa merkkiä, joka antaa kulloisenkin järjestelmän rivierottimen.

Seuraava esimerkki havainnollistaa Comtestin ja JUnitin suhdetta testaten eri rivinvaihtomerkkien käsittelyä.

Comtest:

/**
 * @example
 * <pre name="test">
 * System.lineSeparator() === "\r\n";
 * System.lineSeparator().equals("\r\n") === true;
 * System.lineSeparator().equals("\n") === false;
 * 
 * String mjono = "\t \r\n abc \n";
 * "abc" === mjono.trim();
 * "abc" === mjono.strip();
 * </pre>
 */

TAI (Comtest):

/**
 * @example
 * <pre name="test">
 * #import static org.junit.Assert.assertEquals;
 * #import static org.junit.Assert.assertTrue;
 * #import static org.junit.Assert.assertFalse;
 * 
 * assertEquals(System.lineSeparator(), "\r\n");
 * assertTrue(System.lineSeparator().equals("\r\n"));
 * assertFalse(System.lineSeparator().equals("\n"));
 * 
 * String mjono = "\t \r\n abc \n";
 * assertEquals("abc", mjono.trim());
 * assertEquals("abc", mjono.strip());
 * </pre>
 */
 

JUnit:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class Junit {
    
    @Test
    public void testAll() {
        assertEquals(System.lineSeparator(), "\r\n");
        assertTrue(System.lineSeparator().equals("\r\n"));
        assertFalse(System.lineSeparator().equals("\n"));
    
        String mjono = "\t \r\n abc \n";
        assertEquals("abc", mjono.trim());
        assertEquals("abc", mjono.strip());
    }
}
# stdouttest

15. Tulostuksen testaaminen

Tämä tarvitsee että Ali.jar on projektissa.

Katso Suuntaaja.

Esimerkki:

     * @example
     * <pre name="test">
     * Suuntaaja.StringInput si = new Suuntaaja.StringInput("");  
     * Suuntaaja.StringOutput so = new Suuntaaja.StringOutput();
     * 
     * si.input("ä 8\n8 5\n4 5\n\n");  
     * main(null);
     * String tulos =
     *   "Käytössäsi on 5.0 sekä 8.0 litran astiat ja Ämpari (0.0 l)\n"+
     *   "5.0 litran astiassa on 0.0 litraa nestettä\n" +
     *   "8.0 litran astiassa on 0.0 litraa nestettä\n" +
     *   "Mistä kaadetaan ja mihin >"                   + 
     *   "5.0 litran astiassa on 0.0 litraa nestettä\n" +
     *   "8.0 litran astiassa on 8.0 litraa nestettä\n" +
     *   "Mistä kaadetaan ja mihin >"                   +
     *   "5.0 litran astiassa on 5.0 litraa nestettä\n" +
     *   "8.0 litran astiassa on 3.0 litraa nestettä\n" +
     *   "Mistä kaadetaan ja mihin >"                   +
     *   "Nimeä ei tunneta: 4 tai 5\n"                  +
     *   "Tunnetaan nimet: \n"                          + 
     *   "ä 5 8 \n"                                     +
     *   "5.0 litran astiassa on 5.0 litraa nestettä\n" +
     *   "8.0 litran astiassa on 3.0 litraa nestettä\n" +
     *   "Mistä kaadetaan ja mihin >";
     * 
     * so.ero(tulos) === null; 
     * si.palauta(); so.palauta();
     * </pre>

Tämä saattaa vaatia, että heti luokan alkuun listäään

// #import fi.jyu.mit.ohj2.Suuntaaja;

jotta testitiedostoon tulee oikea import.

16. Tiedostojen testaaminen

Tiedostojen testaamiseksi on joukko apualiohjelmia luokassa VertaaTiedosto.

Esimerkiksi testataan ohjelmaa (eli ajetaan sen main-aliohejlma), jolle komentorivin argumenttina annetaan mitä tiedostoa luetaan (esimerkissä hiljaa.txt ja mihin tiedostoon tulos kirjoitetaan (esimerkissä tulos.txt).

/**
 * Yli 30 alkavien rivien kopiointi.
 * @param args pääohjelman argumentit mistä mihin
 * 
 * @example
 * <pre name="test">
 * #THROWS IOException
 * #import java.io.IOException;
 * #import fi.jyu.mit.ohj2.VertaaTiedosto;
 *  VertaaTiedosto.kirjoitaTiedosto("hiljaa.txt",
 *      "33 hiljaa 1 hiipii\n"+
 *      "hyvä 33 tulee\n"+
 *      "36 1 3 5 55\n"+
 *      "nyt 33 riittää\n");
 *  String tulos =
 *      "33 hiljaa 1 hiipii\n"+
 *      "36 1 3 5 55\n";
 *  VertaaTiedosto.tuhoaTiedosto("tulos.txt"); 
 *  main(new String[]{"hiljaa.txt","tulos.txt"});
 *  VertaaTiedosto.vertaaFileString("tulos.txt",tulos) === null;
 *  VertaaTiedosto.tuhoaTiedosto("tulos.txt");
 *  VertaaTiedosto.tuhoaTiedosto("hiljaa.txt");
 * </pre>
 */

Esimerkissä on luettavasta tiedostosta tulostetaan toiseen tiedostoon rivit joiden alussa on luku joka on suurempi kuin 30. Testin päätteeksi on kohteliasta tuhota testin aikana syntyneet "resurssit". Toki tiedostojen niminä voisi käyttää sellaisiakin, joita ei levyllä voi olettaa etukäteen olevan.

Testin on itse luotava tarvittavat resurssit, se ei voi luottaa siihen, että jokin resurssi olisi olemassa. Esimerkissä VertaaTiedosto.kirjoitaTiedosto tekee tämän. Odotettu tulos on tehty merkkijonoon tulos ja kun pääohjelma on ajettu, verrataan onko syntyneen tulos.txt-tiedoston sisältä sama kuin merkkijonon tulos sisältö (ottaen huomioon mahdolliset erilaiset rivinvaihtomerkit eri järjestelmien välillä). Tämän vertailun tekee esimerkissä VertaaTiedosto.vertaaFileString. Funktio palauttaa null, mikäli sisälöt vastaavat toisiina. Mikäli eivät vastaa, palautetaan merkkijono, jossa on eroavuudet paikat.

Toki main-funktio kutsun tilalla voi olla mikä tahansa muukin aliohjelmakutsu tai metodikutsu.

Pakko kysyä: tuossa on VertaaTiedosto.tuhoaTiedosto("tulos.txt"). Missä tuo "tulos.txt" luodaan? Ylempänä on String tulos mutta se ei kuitenkaan käsittääkseni tule .txt muotoon - ainakin ylempänä esim. "hiljaa.txt" luodaan erikseen. Sitä myöhemmin verrataan tulos-Stringiin.

VL: Tarkensin tekstillä.

16 Mar 23 (edited 16 Mar 23)

17. Vanhat ComTestin versiot

  • Uudet ComTest-versiot, 1.06:sta asti eivät tarvitse alla olevia

  • Lisää johonkin kohti vielä kommentteihin tällaisen testin tapauksessa

     // #STATICIMPORT  

    jotta kääntäjä osaa käyttää poista-metodia oikeasta luokasta ilman viitettä luokkaan. Huom! Kommenttimerkin ja #:n välissä saa olla korkeintaan yksi välilyönti ja sen on oltava välilyönti. JavaDoc kommentteihin kirjoitettuna *-merkin perään taas ei saa olla noita //-merkkejä ettei tule sisäkkäisiä kommentteja. Toki voit kirjoittaa testeissä myös:

     *   Poista.poista("Catcat"   ,"at")  ===  "Cc";

    mutta #STATICIMPORT-rivin ansiosta luokkaa ei ole pakko mainita testeissä. Toinen usein tarvittava import voi olla #CLASSIMPORT, jolloin luokka lisätään import-lauseeseen.

18. Ongelmia

  • joskus kannattaa tuhota vanhat testitiedostot, koska jos ne on saatu rikki, niin ComTest ei uudelleen generoinnissa muuta muita kuin itse kirjoittamiaan osia.
# simplecomtest

19. Yksinkertaisten Comtest-testien suorittaminen yhdellä komennolla bash-ympäristössä

Yksittäisten luokkien Comtest-testien ajamista voi nopeuttaa vähäisellä vaivalla pienellä shell-skriptillä. Menetelmä sopii pienten ohjelmien (joidenkin demovastauksien) ohjelmointiin Linux-ympäristössä tekstieditorilla, mutta sopivilla muutoksilla skriptiä voi toki laajentaa koskettamaan laajempiakin ohjelmia.

19.1 Valmistelut

  • Asenna ensin Comtest ohjeiden mukaisesti ja lue myös sivu käytöstä ilman pluginia

  • Varmista että tarvittavat tiedostot ovat ympäristömuuttujissa:

      #Polut luonnollisesti vaihtelevat koneittain
      echo 'CLASSPATH="$CLASSPATH:/home/username/ohj2/Ali.jar:/usr/share/junit-4/lib/junit.jar:/usr/share/hamcrest-core/lib/hamcrest-core.jar"' >> ~/.bash_profile
  • Luo kansio, joka on PATH-muuttujassa ja jonne voi tallentaa suoritettavia ohjelmia.

      mkdir ~/bin
      echo 'PATH="$PATH:~/bin"' >> ~/.bash_profile
  • Lataa päivitetyt ympäristömuuttujat joko kirjautumalla uudelleen tai kirjoittamalla

      source ~/.bash_profile

19.2 Bash-skripti

Seuraava skripti ei suorita minkäänlaista virheentarkistusta, eli toimivuus on odotettavissa ainoastaan mikäli ohjelma ja testit kääntyvät oikein. Esimerkkitapauksessa skriptin nimenä toimii 'jtest'.

  • Avaa tekstieditorilla kohdetiedosto, esim:

      nano ~/bin/jtest
  • Kirjoita jotain seuraavankaltaista tiedostoon:

      #!/bin/bash
      PREF="jtest:"      #etuliite skriptin tulosteille
      TARGET=${1%.java}  #riisutaan pääte
    
      echo "${PREF} Käännetään ${TARGET}.java ..."
      javac ${TARGET}.java
    
      echo "${PREF} JUnit-testien generointi Comtestilla ..."
      java -jar /home/username/ohj2/comtest.jar ${TARGET}.java
    
      echo "${PREF} Käännetään JUnit-testi ${TARGET}Test.java ..."
      javac ${TARGET}Test.java
    
      echo "${PREF} Ajetaan yksikkötesti ..."
      java org.junit.runner.JUnitCore ${TARGET}Test
  • Lopuksi vielä tee tekstitiedostosta suoritettava

      chmod +x ~/bin/jtest

19.3 Käyttö

Jos valmistelut sujuivat onnistuneesti, käytön pitäisi toimia seuraavasti:

jtest Yksikko.java

Joka tuottaa esimerkiksi seuraavannäköistä ulostuloa:

jtest: Käännetään Yksikko.java ...
jtest: JUnit-testien generointi Comtestilla ...
Yksikko.java => /home/username/ohj2/demo5/YksikkoTest.java ok
jtest: Käännetään JUnit-testi YksikkoTest.java ...
jtest: Ajetaan yksikkötesti ...
JUnit version 4.6
.
Time: 0.003

OK (1 test)

19.4 Mallikerhon testaaminen komentoriviltä

  1. Lataa comtest.jar hakemistoon \devel\jar nimellä comtest.jar

  2. Lataa junit.jar hakemistoon \devel\jar nimellä junit.jar

  3. Hae kerho versionhallinnasta

     svn export https://svn.cc.jyu.fi/srv/svn/ohj2ht/k2019/vesal/trunk/
     cd trunk
  4. Käännä testattavat luokat JUnit-testejä varten

     javac -d bin -cp \devel\jar\Ali.jar;\devel\jar\fxgui.jar --module-path \devel\javafx\lib --add-modules javafx.fxml,javafx.controls,javafx.web src\kanta\*.java src\kerho\*.java src\fxKerho\*.java
  5. Luo JUnit-testit makrokielen mukaisista kommenteista

     java -jar \devel\jar\comtest.jar src\kanta\*.java src\kerho\*java src\fxKerho\*.java
  6. Käännä testattavien luokkien JUnit-testit

     javac -d bin -cp \devel\jar\Ali.jar;\devel\jar\fxgui.jar;\devel\jar\junit.jar;bin --module-path \devel\javafx\lib --add-modules javafx.fxml,javafx.controls,javafx.web src\kanta\test\*.java src\kerho\test\*.java src\fxKerho\test\*.java src\test\*.java
  7. Aja testit

     cd bin
     java -cp .;\devel\jar\junit.jar;\devel\jar\Ali.jar org.junit.runner.JUnitCore test.AllTests

    pitäisi tulostaa

     JUnit version 4.10
     ................................................................................
     ..................................................
     Time: 0,484
    
     OK (130 tests)

These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.