- TIE-0240x
- 8. Olioiden elinkaari: kopiointi, sijoitus, siirtäminen
- 8.2 Harjoitus: Koodin laatu
Harjoitus: Koodin laatu¶
Harjoituksissa opetellaan virheiden löytämistä ja korjaamista koodista Qt:n yksikkötestauskehyksen, debuggerin, keskeytyskohtien (breakpoint) ja debug-tulostuksien avulla.
Debugattava koodi on käytössä (lähes) sama päiväysluokka kuin aiemmin harjoituksissa. Lisäksi käytössä on yksikkötestit ja SonarQuben tuottama staattinen analyysi koodista. Tarkoitus on yksikkötestien avulla löytää, paikallistaa ja korjata luokkaan tarkoituksella tai vahingossa upotetut bugit.
Harjoituksessa tulee vastata muutamaan kysymykseen. Harjoitus on kuitenkin muutenkin hyödyllinen mieleenpalauttelu debuggaamisesta.
Tehtävän vaatimat tiedostot saat nyhtämällä versionhallinnasta. Ne sijaitsevat repositoriossa ``student_template_project` https://course-gitlab.tuni.fi/tie-0240x-ohjelmointi-3-programming-3-2020-2021/student_template_project. Se tulee laittaa paikalliseen repositorioosi remoteksi. Tässä harjoituksessa tarvitsemasi koodit ovat hakemistossa EX_debug. Huomaa, sinulla ei ole oikeuksia päivittää repositoriota.
Saat koko komeuden auki päätason projektista WE-debugging.pro.
WE-debugging.pro
DateProject
DateProject.pro
main.cc, date.hh, date.cc
UnitTest
UnitTest.pro
tst_unittest.cc
Virheiden havaitseminen¶
Kun käännät (build) ylimmän tason projektin, QtCreator kääntää sekä itse "sovelluksen" että yksikkötestit. Valitsemalla aliprojektin ja sieltä ajamisen (run), ajaa QtCreator valitusta aliprojektista riippuen joko itse "sovelluksen" tai yksikkötestit.
Tässä harjoituksessa riittää, että keskitytään virheisiin, jotka valmiina annettu yksikkötestaus havaitsee. Testejä voi toki kirjoittaa myös lisää, ja yksityiskohtaisemmat testit voivat jossain tapauksessa jopa helpottaa virheen paikallistamista. Yksikkötestin ajaminen siis riittää haluttujen virheiden ilmi tulemiseen. Huomaa kuitenkin, että yksi bugi saattaa tietysti aiheuttaa usean testitapauksen epäonnistumisen, ja vastaavasti testitapauksen epäonnistuminen saattaa johtua useammasta kuin yhdestä bugista (eli vaikka yhden bugin löytää ja korjaa onnistuneesti, testitapaus saattaa edelleen epäonnistua).
SonarQuben staattinen analyysi¶
Pääset katsomaan SonarQuben analyysitulosta täältä. Tutustu SonarQuben analyysiin.
Koodihajut (code smell) ovat mikä tahansa kohta koodissa, jossa mahdollisesti piilee jokin syvempi ongelma. Hajut eivät siis välttämättä ole bugeja. Niissä ei tarvitse olla toiminnallisesti mitään vikaa. Ne kuitenkin osoittavat kooditasolla epäselvyyttä, heikkoutta tai muuta vikaa, joka joko haittaa kehittämistä tai nostaa bugiriskiä, ts. haisevat pahalle.
Tekninen velka taas kuvaa tarvittavan toteutuksen parantamisen määrää. Tähän työhön lasketaan refaktorointi, toteutuksen tekninen parantaminen ja selkeyttäminen sekä muu vastaava ylläpito työ. Tekninen velka katsotaan työksi, joka jossain kohtaa on tehtävä, jos halutaan välttää ongelmia. Velka on siis maksettava takaisin.
Tässä hyödyllisintä tietoa saat kattavuutta tutkimalla. Kattavuus kertoo tilanteesta, jossa yksikkötestit on ajettu kerran release-moodissa. Klikkaa kattavuusprosenttia niin pääset katsomaan kattavuutta tiedostotasolla.
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Virheiden etsintä ja testitulostukset¶
Joskus debuggauksen yhteydessä on hyödyllistä lisätä testitulostuksia, joissa selviää muuttujien arvoja ja sitä, missä ohjelma on menossa. Qt:ssä on omat olionsa debug-tulostuksiin. (Usein kuitenkaan pelkät testitulostukset eivät riitä, vaan kannattaa (myös) käyttää debuggeria ja sen keskeytyskohtia).
qDebug
on funktio, jonka palauttamaan olioon voi tulostaa tuttuun tapaan <<-operaattorilla. Tulostuksen loppuun tulee automaattisesti rivinvaihto ja tulostettavat asiat erotetaan sanaväleillä:
#include <QtDebug>
...
qDebug() << "Muuttujan arvo on" << a << "ja toisen" << b;
Qt:n debuggerin käyttö¶
Yksikkötestit saa ajettua QtCreatorin debuggerissa, kun painaa vasemmalla alhaalla olevaa "vihreä nuoli+ötökkä"-nappulaa (ja on ensin sen yläpuolelta on valinnut, että haluaa ajaa yksikkötestit ja debug-tilassa).
QtCreator siirtyy debug-tilaan, jossa käytössä on mm. seuraavanlaisia työkaluja (tarkempia ohjeita täältä):
- Ohjelman senhetkinen suorituspaikka näkyy koodi-ikkunan vasemmassa laidassa nuolena.
- Kutsujälki (call trace/stack) -ikkuna koodi-ikkunan alla näyttää, missä kohdin ohjelmaa ollaan menossa. Ikkunassa näkyy senhetkinen funktioiden kutsuhierarkia, ja hierarkian riviä tuplaklikkaamalla koodi-ikkuna (ja data-ikkuna) siirtyy näyttämään ko. funktiota.
- Askellus- ja ajonappulat löytyvät kutsujälki-ikkunan yläreunasta.
- Vihreä pallo jatkaa ohjelman suoritusta
- Punainen neliö lopettaa debuggauksen. Käytä tätä, jotta debuggattava ohjelma ei jää taustalle lillumaan ja muistia tuhlaamaan.
- "Step over"-nappula suorittaa ohjelmaa, kunnes tullaan seuraavalle koodiriville. (Se jatkaa suoritusta funktiokutsujen "yli".)
- "Step into"-nappula suorittaa ohjelmaa, kunnes tullaan seuraavalle koodiriville, ja se pysähtyy myös, jos suoritus siirtyy toiseen funktioon. (Hypätään funktion "sisään".)
- "Step out"-nappula suorittaa ohjelmaa, kunnes senhetkisestä funktiosta palataan.
- Keskeytyskohtia (break point) voi lisätä klikkaamalla koodi-ikkunassa rivinumeron vasemmalle puolelle. Tämä lisää/poistaa keskeytyskohtaa merkitsevän punaisen pallon (keskeytyskohdat näkyvät myös listana kutsujälki-ikkunan oikeassa laidassa). Kun ohjelmaa suoritetaan debuggerissa, suoritus pysähtyy jokaisen keskeytyskohdan kohdalla. Valitsemalla keskeytyskohdasta hiiren oikealla napilla "edit breakpoint" voi keskeytyskohdan mm. muuttaa ehdolliseksi (condition), jolloin pysähtyminen tapahtuu vain, jos syötetty ehto on tosi. Toinen kätevä tapa on säätää, montako kertaa (ignore count) keskeytyskohtaan pitää tulla, ennen kuin pysähdytään.
- Data-ikkuna näkyy koodi-ikkunan oikealla puolella. Siinä näkyvät kaikkien paikallisten muuttujien ja olion omien jäsenmuuttujien arvot. Jos viimeisin suoritettu toiminto on "step out", ikkunassa näkyy myös funktion paluuarvo.
Lisäjuttu: CI mukaan¶
Halutessasi voit lisätä myös tämän harjoituksen testit osaksi CI:tä (sinnehän yksikkötestit kuuluvat).