Kurs VBA – cz. 20 – Debugging

W ramach kursu napisaliście już nie jeden program i na pewno spotkaliście się z niejednym błędem, który sprawiał, że program nie działał jak powinien. Wszystkie rodzaje błędów jakie możecie napotkać opisałem w cz. 18 – Obsługa błędów. Kiedy już znajdziemy błąd, uporanie się z nim jest stosunkowo proste. Właśnie szukanie ich zajmuje programistom dużo czasu i przyprawia o siwiznę.
Z pomocą przychodzi debugowanie. Nazwa jest może trochę niefortunna, ale powszechnie używana w Polsce. Jest to proces uruchamiania programu krok po kroku w celu znalezienia błędów (bugów) lub po prostu przeanalizowania działania programu.

Powyższa, nieco lakoniczna definicja może być niezrozumiała. Spróbujmy więc debugowania samodzielnie, krok po kroku.

Stwórzmy nowy skoroszyt z najprostszym makrem:

Powyższy program przegląda dziesięć komórek i wpisuje numer wiersza lub losową liczbę, zależnie, czy numer wiersza jest parzysty, czy nie. Po uruchomieniu makra w ułamku sekundy komórki wypełniają się liczbami i pojawia się komunikat. Chcielibyśmy jednak krok po kroku przeanalizować działanie programu.

Ustawianie breakpoint

W tym przypadku także posługiwać się będę popularną anglojęzyczną nazwą breakpoint. Można to najłatwiej przetłumaczyć jako punkt przerwania, przerwania działania programu, Breakpoint ustawiamy na jednej z linii naszego programu. Jeżeli program dotrze do tej linii, zatrzyma wykonanie i przeniesie nas do VBE.

Break point ustawiamy na dwa sposoby:

Kliknięcie prawym klawiszem na linię
Kliknięcie lewym klawiszem na pasek z lewej strony

Jak widać nasza linia została zaznaczona na czerwono, oraz z lewej pojawiła się czerwona kropka.

Spróbujmy teraz uruchomić nasze makro. Możemy to zrobić jednym ze sposobów przedstawionych wcześniej lub klawiszem F5, albo zielonym klawiszem Play (omówiony poniżej). Komunikat zakończenia działania nie pojawia się, za to edytor VBE wygląda jak poniżej. Linia, w której ustawiliśmy breakpoint jest zaznaczona na żółto i pojawiła się z lewej strony żółta strzałka. W ten sposób jest oznaczona linia, która wykona się następna, jeżeli pozwolimy programowi wykonać się dalej.

Działanie programu przerwane na zaznaczonej linii

Kontrolowanie przebiegu programu

Spójrzmy teraz na ikony na górnym pasku.

Ikonki te pozwalają nam kontrolować przebieg programu. Kliknięcie ikonki „play” kontynuuje działanie. Wykona się zaznaczona linia i wszystkie kolejne, aż znowu napotkany zostanie breakpoint lub program zakończy działanie. Ikonka stop przerywa działanie makra.

Po kliknięciu play pojawi się nasz komunikat, po kliknięciu stop nie dzieje się nic, ponieważ nie wykona się linia wyświetlająca MsgBox.

Ustawmy teraz breakpoint na poniższej linii i uruchommy makro:

Zaznaczona linia jest zaznaczona na żółto i oznaczona strzałką. Będziemy teraz analizować program krok po kroku. Można to robić przy pomocy kilku skrótów klawiaturowych, zobaczmy co się stanie po użyciu kolejnych skrótów:

 shift + F8
Aktualnie zaznaczona linia zostanie wykonana i zostanie zaznaczona kolejna:

F8

Zaznaczona linia zostanie wykonana. Jeżeli aktualnie zaznaczona jest procedura, wykonywanie przenosi się do wnętrza tej procedury. Jest to zasadnicza różnica w stosunku do skróty shift+F8, w którym wykonywanie nie jest przenoszone do wnętrza procedury. W poprzednim przypadku oczywiście wnętrze funkcji też jest wykonywane, jedynie nie jest pokazywane krok po kroku.
Powyższe może być trochę nieczytelne na pierwszy rzut oka ponieważ wykonywanie programu przeskakuje pomiędzy procedurą test a funkcjami, które wywołuje.
Naciśnięcie tego skrótu kiedy makro nie jest uruchomione, wykonywanie jest rozpoczynane i przerywane na pierwszej linii programu.

ctrl + shift + F8

Po użyciu tego skrótu wszystkie polecenie wewnątrz aktualnie wykonywanej procedury są uruchamiane i wykonywanie zatrzymuje się na pierwszym poleceniu po wywołaniu danej procedury.

Na ten wypadek zmodyfikowałem trochę nasz przykładowy program, funkcja zawiera kilka więcej poleceń.

F5

Wykonanie programu jest uruchamiane do momentu napotkania następnego breakpoint , Debug.Assert, stop (poniżej) lub zakończenia programu. Ten skrót działa tak samo jak naciśnięcie zielonej ikony play.

Ustawianie watch

Doskonałą funkcjonalnością VBE jest podglądanie wartości zmiennych podczas wykonywania programu. Watch’em może  być dowolna zmienna, atrybut obiektu lub całe wyrażenie. Watch możemy ustawić przed uruchomieniem makra, lub już podczas wykonywania. Będę dalej posługiwał się angielską nazwą karkołomnie odmienianą w języku polskim.

Dodam teraz do naszego programu operację na zmiennej i, którą będziem obserwować

Jeszcze przed uruchomieniem makra zaznaczam dowolne wystąpienie zmiennej i, klikam prawym klawiszem i wybieram Add Watch. 

W okienku pod kodem (zatułowanym Watches) pojawiła się nowa linia.

W pierwszej kolumnie jest nazwa naszej zmiennej. W drugiej kolumnie nic nie jest napisane , program jeszcze się nie wykonuje więc nasza zmienna nie może mieć żadnej wartości. W trzeciej kolumnie (Type) pojawi się typ zmiennej, sami go zadeklarowaliśmy w programie. Ostatnia kolumna (Context) określa widoczność zmiennej (procedura test w module o nazwie sheet2).

Dla bardziej skomplikowanych zmiennych pojawia się struktura drzewa.

Powtórzmy dodawanie watch’a dla zmiennej lr_Komorka

Ustawię teraz breakpoint na początku pętli FOR i uruchomię makro. Moje okno watches wygląda teraz tak jak powyżej.

Przed pierwszym wykonaniem pętli przy zmiennej lr_Komorka napisane jest Nothing ponieważ pierwsza komórka zakresu A1:A10 nie została jeszcze przypisana do lr_Komorka.Klawiszem F8 wchodzę do wnętrza pętli, zaszło już przypisanie pierwszej komórki zakresu Range(gs_EdytowanyZakres) do zmiennej lr_Komorka.

Zmienne i oraz lr_komorka

 

Zobaczmy jakie mamy możliwości przeglądania obiektu. Na lewo od nazwy lr_Komórka pojawił się krzyżyk, który możemy kliknąć, żeby zobaczyć wszystkie atrybuty obiektu lr_Komórka, czyli wszystkie atrybuty klasy Range. Jeżeli któryś z atrybutów jest klasą, to możemy go także rozwinąć, żeby zobaczyć jego atrybuty itd.
Bezpośrednio na prawo od nazwy zmiennej widzimy atrubut domyślny obiektu, w tym przypadku jest to wartość komórki. Na początku nic tam nie widzimy, ale po wykonaniu przypisania:
pojawi tam się wartość 1.

Samodzielnie przechodź przez kolejne wykonania pętli For i zobacz jak zmienia się wartość zmiennej i W każdym przejściu pętli jest większa o 1.

 

Spróbuj dodać jako watch wyrażenie lr_Komorka.Row Mod 2 korzystając z menu. W kolejnych wykonaniach pętli jest ono równe 1 lub 0. Wyrażenie to jest sprawdzane w naszym kodzie na początku pętli, ale w podglądzie wyświetlane jest cały czas. Dzięki temu jako watch możemy ustawić dowolne wyrażenie, nie tylko takie, które rzeczywiście pojawia się w kodzie.
Dodawanie watch przez menu

Podglądanie wartości zmiennych bez Watch’a

Podczas debugowania nie trzeba dodawać watchy, aby podejrzeć co jest pod określoną zmienną. Wystarczy najechać na nią myszką:

Klasa Debug

Wbudowana klasa debug udostępnia dwie metody przydatne do analizy programu. Pierwsza to print. Drukuje ona w okienku immediate edytora VBE. Jeżeli nie widzisz okna immediate, włącza się w górnym menu: view/immediate window.

Dodaj dodatkową linię do programu:

Po wykonaniu całego programu w oknie immediate pojawią się kolejne wartość komórki przypisanej do lr_Komorka:

Druga metoda to debug.assert, służy ona do warunkowego zatrzymania programu. Program zostaje przerwany kiedy warunek umieszczony po assert przestaje być prawdziwy,

Polecenie:

spowoduje przerwanie działania programu kiedy i przestaje być mniejsze niż 5.

Debug.Assert można użyć, kiedy np. jakaś pętla wykonuje się wiele razy i chcemy zatrzymać się na konkretnym przejściu. Możemy też w ten sposób wyłapać jakiś problem, który nie wiemy kiedy dokładnie występuje.

Oczywiście polecenie Debug.Assert False zawsze zatrzymuje program a Debug.Assert True nigdy programu nie przerwie.

Polecenie STOP

Polecenie Stop działa tak jak Debug.Assert False, czyli zawsze zatrzymuje działanie programu,

Oczywiście, jeżeli program piszemy dla kogoś innego należy usunąć polecenia stop i użycie klasy debug przed przekazaniem pliku.

Na koniec

Nie będę ukrywał, że poniższy wpis powstawał z dużymi przerwami przez parę miesięcy, mam nadzieję, że ilość informacji to czytelnikom wynagrodzi. Jeżeli znajdziecie powyżej jakieś błędy, braki, niekonsekwencje lub potrzebujecie dodatkowych wyjaśnień w którymkolwiek punkcie, proszę śmiało pisać.

 

 

Dodaj komentarz

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