Debuggaus

Tässä esitellään lyhyesti debuggauksen tarkoitus ja Riderin tärkeimmät debuggaustoiminnot. Vaikka jokaisessa kehitysympäristössä on omat debuggaustapansa, ovat periaatteet hyvin pitkälti yhteisiä eri ympäristöjen välillä.

Tämä sivu sisältää täydennyksiä monisteen lukuun 10.2 Debuggaus.

Tämä sivu kuuluu myös Ohjelmointi 1 -kurssin debuggausnäytteen esitietoihin. Lue tämä sivu huolellisesti ennen debuggausnäytteeseen tulemista. Syksyn kurssilla debuggausta on harjoiteltu myös pääteohjauksessa 5.

Muita Rider-ohjeita:

1. Miksi pitää debugata?

Jos ohjelmassa on jotakin vikaa (ohjelmointivirhe eli bug), debuggeri on usein helpoin vaihtoehto vian löytämiseksi (virheenjäljitys eli debug). Ohjelmaa voi debugata myös lisäämällä sinne tänne ylimääräisiä tulostuslauseita, mutta debuggerin avulla ohjelmakoodiin ei tarvitse tehdä muutoksia. Debuggerin avulla ohjelma voidaan myös pysäyttää haluttuun kohtaan ja tutkia muuttujien senhetkisiä arvoja, mahdollisesti jopa muuttaa niitä ennen kuin ohjelman suorittamista taas jatketaan. Tämä ei ole mahdollista tulostuslause-tyylisessä debuggauksessa.

Ohjelmointia opetellessa debuggeri on myös oiva väline askeltaa silmukoita, ehtoja ja aliohjelmia ja näin havainnollistaa ohjelman kulkua itselleen.

2. Debuggaustila Riderissa

MacOS-käyttäjät! Näppäinoikotiet ovat oletuksena erilaiset, ne näkee Run-menun alta. Opettele oman järjestelmäsi pikanäppäimet tai vaihda näppäinoikotiet alla olevan ohjeen mukaisesti.

[9.3.2023] Jos olet ottanut käyttöön Riderin uuden UI:n niin debuggaustila ei välttämättä toimi. Vaihda siis takaisin vanhaan UI:hin tai kokeile ehdotettuja korjauksia täältä.

Rider työkalupalkki:


Alla olevat näppäinkomennot ovat Visual Studiolle. Jos Riderissa valitsit näppäinoikoteiden (hot key, keyboard shortcut) asetuksiksi Visual Studion, niin silloin nämä toimivat myös Riderissa. Riderin näppäinoikotiet saa muutettua Configure -> Settings -> Keymap tai File -> Settings -> Keymap. HUOM! Vaikka tässä kohtaa puhutaan Visual Studiosta, tehtävä tehdään Riderilla, ei Visual Studiolla eikä varsinkaan Visual Studio Codella.

Toiminto Näppäin Win Näppäin Mac
Debug F5 ⌥ F5
Step Into F11 ⌘ F11
Step Over F10 F10
Resume F5 F5
Stop debugging Shift+F5 ⇧ F5

Macin painikkeet:

  • ⌘ = cmd
  • ⏎ = enter
  • ⌥ = alt
  • ⇧ = vaihto (shift)

Huomaa, että toiminnot voi myös ohjelmoida itse melkein mihin tahansa painikkeisiin.

Debuggaustila käynnistetään painamalla F5. Tällöin ohjelma voidaan milloin tahansa pysäyttää, tai lisätä ohjelmakoodiin keskeytyskohta (breakpoint) ja näin pysäyttää ohjelma haluttuun kohtaan. Jos ohjelmassa ei ole yhtään breakpointtia, vaikuttaa debugtilassa ajo samanlaiselta kuin "normaalissa" (release-tila, ei-debuggaus) suoritustilassa. Release-ajo saadaan käyntiin painamalla Ctrl-F5.

Tarkasti ottaen debug- (F5) ja release-käännökset (Ctrl-F5) tehdään hieman eri tavalla, ja release-käännetty koodi optimoidaan käytännössä hieman nopeammaksi. Tämän kurssin kannalta nopeuserolla ei kuitenkaan ole merkitystä.

Debug-tila on kätevä myös pelien ongelmia selvitettäessä. Laita peli käyntiin debuggaustilassa (F5), ja kun pelioliot ovat tulleet näytölle käydään lisäämässä epäiltyyn ongelmapaikkaan koodiin breakpoint.

Samoin jos ohjelma tuntuu olevan totaalisen jumissa, voidaan sen ajo pysäyttää ja katsoa, missä kohti ohjelmaa ollaan menossa ja näin ehkä voidaan ratkaista, mistä ohjelman "jumi" johtuu.

3. Debuggaustoiminnot

# breakpoint

3.1 Keskeytyskohta, breakpoint

Voit laittaa ohjelmaan keskeytyskohdan eli ''breakpointin'', jonka tarkoituksena on keskeyttää ohjelman suoritus haluttuun kohtaan. Toisin sanoen, ohjelma suoritetaan alusta siihen saakka, kunnes tullaan keskeytyskohtaan, johon suoritus sitten pysähtyy.

Riderissa vie hiiri ikkunan vasempaan reunaan rivinumeroiden ja koodin väliin. Jos käytät New UI -käyttöliittymää, klikkaa rivinumeron kohdalle.

Keskeytyskohtaa EI voi asettaa Riderissä tyhjille riveille, kommenttiriveille eikä esittelyriveille. Toisin sanoen keskeytyskohdan voi asettaa vain suoritettaville riveille.

Aseta breakpoint
Aseta breakpoint

Paina hiirellä keskeytyskohta haluamaasi kohtaan.

3.2 Debuggaustilan käynnistäminen

Ohjelma käynnistyy debuggaustilaan painamalla joko F5, klikkaamalla oikean ylälaidassa olevaa Debug painiketta tai valitsemalla valikosta Run -> Debug. Tällöin ohjelman suoritus "pysähtyy" ensimmäiseen asettamaasi keskeytyskohtaan.

Huomaa, että keskeytyskohdan osoittaman punaisen pallon vieressä on nyt myös keltainen nuoli, joka näyttää seuraavaksi suoritettavan rivin. Toisin sanoen, ohjelman alkuosa on suoritettu rivi riviltä normaaliin tapaan, ja suoritus pysähtyy keskeytyskohtaan siten, että seuraavaksi suoritusvuorossa on tutkittava rivi, jolle keskeytyskohta on asetettu. Korostan: tätä keltaisen nuolen osoittamaa asiaa ei ole vielä suoritettu.

On mahdollista suorittaa ohjelma myös ilman debuggausta (Ctrl + F5 tai valitsemalla Run). Tällöin keskeytyskohdat jätetään huomiotta. Toisaalta myös esimerkiksi poikkeuksia (exceptions) ei käsitellä Riderin avulla, vaan ohjelmat voivat kaatua hallitsemattomasti.

# askellus

3.3 Askellus (Step into, Step over)

Koodia voidaan askeltaa rivi kerrallaan. Tällöin ohjelman suoritus etenee debuggaustilassa rivi kerrallaan eteenpäin. Askellukseen on kaksi erilaista tapaa

  • Step into (F11), askelletaan myös kutsuttavien aliohjelmien koodi riveittäin
  • Step over (F10), aliohjelmakutsujen koodi suoritetaan kerralla ilman askellusta, eli tavallaan hypätään aliohjelman yli

Step over -toimintoa kannattaa käyttää sellaisen aliohjelmakutsun kohdalla, jonka sisäistä logiikka ei ole tarkoitus tarkastella. Esimerkiksi Console.WriteLine- aliohjelmakutsun kohdalla kannattaa mieluummin valita Step over kuin Step into, sillä meitä ei oikeastaan kiinnosta tuon aliohjelman toiminta.

3.4 Resume

Resume-toiminto jatkaa ohjelman suorittamista normaaliin tapaan. Mikäli ohjelmassa on myöhemmin keskeytyskohta, ohjelman suoritus keskeytyy siihen.

3.5 Debuggaustilan lopettaminen (ohjelman ajon lopettaminen)

Debuggauksen voi lopettaa painamalla Shift + F5 tai valikosta Run -> Stop debugging.

3.6 Muuttuja-arvot (locals)

Debuggaus‐näkymän Threads & Variables-paneelissa (tai välilehdellä) näkyy tällä hetkellä näkyvissä olevat muuttujat ja niiden arvot.

Paikalliset muuttujat kuvassa punaisella korostetun alueen sisällä
Paikalliset muuttujat kuvassa punaisella korostetun alueen sisällä

Locals-paneelissa voi myös muokata muuttujien arvoja ajonaikaisesti. Esimerkiksi muuttujan "luku"-arvoa voi muokata kaksoisklikkaamalla Value-sarakkeen kohdalta numeroa ja kirjoittamalla uuden luvun vanhan tilalle. Tämän jälkeen kannattaa painaa Enteriä, jotta editori ottaa muutoksen. Riderissa muuttujan arvoa voi locals-ikkunassa muokata painamalla F2 tai klikkaamalla hiiren oikealla ja valistemalla Set Value.

Arvon muuttaminen Riderissa
Arvon muuttaminen Riderissa

Huomautus double-tyyppisen arvon muuttamisesta: Double-tyyppisen muuttujan arvoa muutettaessa on arvoksi asetettava desimaaliluku, esimerkiksi 3.0. Mikäli asetat arvoksi kokonaisluvun, esimerkiksi 3, debuggeri antaa virheilmoituksen "Error: Size of source and of dest differ".

JetBrains Rider: muuttujan arvoa voi muokata locals-ikkunassa painamalla F2 tai oikeaklikkaamalla ja valitsemalla Set Value. -JuhoK

14 Oct 20

3.7 Call stack, kutsupino

Jos saa ison ohjelman tutkittavakseen ja pitää korjata jotakin kohtaa eikä tiedä mistä ko. kohtaan tullaan, niin jälleen debuggeri on avuksi. Laita keskeytyskohta (breakpoint) tutkittavaan kohtaan, sitten ohjelma käyntiin (paina F5) ja kun ohjelma pysähtyy laittamaasi keskeytyskohtaan, niin kutsupinosta (Call Stack) voidaan katsoa reitti, mistä pysäytyskohtaan on päädytty.

Jos kutsupinoa ei näy Debug-näkymässä, saa sen esille valitsemalla klikkaamalla paneelin oikeassa yläreunassa olevaa ikkunan näköistä kuvaketta: Layout settings -> Threads Frames -> Side by side.

Riderissa Thread & Variables -paneelissa näkee kutsupinon
Riderissa Thread & Variables -paneelissa näkee kutsupinon

Riderin kutsupinossa ei valitettavasti näy lähdekoodin rivinumeroita siitä, miltä riviltä kutsuun on lähdetty. Mutta klikkaamalla kutsupinossa hiiren oikealla, voidaan ottaa pinon sisältä leikepöydälle ja sitten tarkastella sitä rivinumeroineen jossakin editorissa.

# watch

3.8 Watch

Paikallisten muuttujien lisäksi voidaan suorituksen aikana seurata itse valittuja muuttujia Add to Watches toiminnolla. Yksittäisten muuttujien lisäksi voidaan tarkastella lausekkeita, esimerkiksi taulukko[i] > suurin (tuottaisi true tai false).

  1. Aseta keskeytyskohta haluamaasi paikkaan ja aloita debuggaus.
  2. Etsi koodista se muuttuja (tai lauseke), jonka tilaa haluat tarkkailla ajon aikana. Valitse se (maalaamalla esimerkiksi hiirellä), klikkaa sitten hiiren oikealla ja valitse Add to Watches. Alla olevassa kuvassa lisätään suurin-muuttuja locals/watch-paneeliin.
Watch1
Watch1
Watch2
Watch2
  1. Voit lisätä eri "watcheja" haluamasi määrän. Alla lisätään myös i, taulukko[i] ja taulukko[i] > suurin watch-paneeliin.

Huomaa, että watch-paneeliin lisäämäsi muuttuja (tai lauseke) ei välttämättä ole olemassa (ts. ei ole luotu tai ei "näy" sillä hetkellä), joten luonnollisestikaan tilaa ei voida tällöin tutkia. Alla olevassa kuvassa suoritus on menossa vasta rivillä 10.

Watch3
Watch3

Tässä esimerkissä i, taulukko[i] ja taulukko[i] > suurin ovat paikallisia muuttujia (lausekkeita) EtsiSuurin-lohkossa ja tulevat näkyviin kun ohjelman suoritus etenee sinne saakka.

Watch4
Watch4

Nyt watch-ikkunasta on helppo tarkastella esimerkiksi taulukon arvoja sitä mukaa kun silmukka etenee.

Watch5
Watch5
# valuechange

3.9 Muuttujan arvon muuttaminen

Tarvittaessa muuttujan arvoa voi muuttaa esim Locals-ikkunassa klikkaamalla arvoa ja sitten antamalla sille uuden arvon.

# ehdollinen

3.10 Ehdollinen keskeytyskohta

Debuggerin avulla voidaan lisätä myös keskeytyskohdalle keskeytymisen ehto. Tällaista keskeytyskohtaa kutsutaan nimellä ehdollinen keskeytyskohta. Sen avulla debuggeri keskeyttää ohjelman suorittamisen vain, kun keskeytyskohtaan annettu ehto toteutuu. Ehto voi olla mikä tahansa totuusarvoinen lauseke, esimerkiksi muuttujan tietty arvo.

Tämä on hyödyllistä etenkin ohjelmassa jossa on esimerkiksi pitkä silmukka, joka halutaan pysäyttää jossain tietyssä kohdassa. Jos ohjelma pysähtyisi jokaisella kierroksella, olisi hyvin työlästä ajaa ohjelmaa haluttuun pisteeseen. Ehdon voi lisätä seuraavasti:

  1. Siirry haluamallesi riville koodissa

  2. Siirry rivinumeron koodiin väliin ja klikkaa siihen breakpoint (näkyy punaisena täplänä)

  3. Paina breakpointin kohdalla hiiren oikeaa näppäintä saadaksesi esiin valikon

  4. Lisää Condition tekstikenttään lauseke, joka saa ajon aikana arvon true tai false, esimerkiksi

    luku == 4

    Sen sijaan

    int luku = 4 

    ei ole ehto, eikä kenttään voi myöskään laittaa if-sanaa. Kun lauseke saa arvon true debuggeri keskeyttää ohjelman suorittamisen. Muutamia muita esimerkkejä ehdoista:

    i > 3
    luvut[i+2] != 3
    pallot[i] == null
  5. Debuggaa (F5)

  6. Kun pysähtyy, tarkastele Locals- ja Watch-ikkunoista muuttujien arvoja ja jatka tarvittaessa Step into (F11), Step over (F10) tai Resume (F5).

Macilla ehdollinen Breakpoint asetetaan “New Breakpoint” komennolla kun avaa hiiren oikealla. https://docs.microsoft.com/en-us/visualstudio/mac/debugging?view=vsmac-2019

23 Oct 20

3.11 Hit Count

Hit Countilla voit laittaa ehdon niin, että kun näin monennen kerran tullaan keskeytyskohtaan, niin silloin pysähdytään.

4. Ongelmia debuggaustilan käynnistymisessä?

4.1 class com.intellij.util.ui.components cannot be cast

Mikäli saat debuggauksen aikana Riderissa poikkeuksen, esim.

class com.intellij.util.ui.components.BorderLayoutPanel 
cannot be cast to class com.intellij.ui.OnePixelSplitter

kokeile asetusten resetointia seuraavien ohjeiden mukaisesti

HUOM! Näin tekemällä menetät kaikki asetuksesi, kuten näppäinoikotiet sekä teemat. Ota asetuksistasi halutessasi varmuuskopiot File -> Manage IDE Settings -> Export Settings.

  • Paina Shift+Shift (eli kaksi kertaa Shift-painiketta) tai Ctrl+T,
  • kirjoita Restore Default settings ja valitse ko. toiminto
  • Rider käynnistyy uudestaan, valitse haluamasi asetukset.

4.2 Rider clr load callback is already in error state. A debug component is not installed

Jos saat yllä mainitun virheilmoituksen kun yrität käynnistää debuggerin niin ongelmana on todennäköisesti, että Mac-koneelle on asennettu väärä versio Riderista.

Joudut siis asentamaan Riderin uudestaan:

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