Jaskinie Podróże Nurki Grafika Mizar Teksty Kulinaria Lemkov Namiary Mapa RSS English
Spelunka Trybików Teksty Testowanie Wykrywanie traconej pamięci a DUnit YAC Software
  Wróć

Spis

Charsets

Wykresy

DBExpress

Delphi

HTML

Intraweb

MSTest

PHP

Programowanie

R

Rhino Mocks

Software

Testowanie

Testowanie UI

VB.NET

VCL

WPF

Wykrywanie traconej pamięci a DUnit
DUnit (biblioteka obsługująca unit testy pod Delphi) posiada miłą opcję wykrywania przecieków pamięci podczas wykonywania testów; tzn. sprawdza całkowitą ilość zaalokowanej pamięci przed uruchomieniem testu i po jego zakończeniu, a gdy druga wartość jest większa od pierwszej, zgłasza (opcjonalnie) błąd wykonania testu.

Aby włączyć tę funkcjonalność w DUnit, należy skorzystać z pozycji Fail TestCase if memory leaked pod menu Options.

Niestety, program może zacząć zgłaszać błędy, na pierwszy rzut oka, nieprawidłowo. Mianowicie wtedy, gdy podczas testu alokowana jest pamięć, która jest zwalniania nie w samym teście, ale później, np. przy zamykaniu programu.

Dzieje się tak często z wywołaniami systemowymi, bibliotekami zewnętrznymi, czy interfejsami GUI (choć, rzecz jasna, może się pojawić przy korzystaniu z własnego kodu). Wszak typowym rozwiązaniem stosowanym w programowaniu jest alokacja pamięci w sposób "leniwy" - przy pierwszym wywołaniu procedury/funkcji czy przy pierwszym odwołaniu do obiektu/klasy, które wymagają dodatkowej pamięci. A pamięć w ten sposób przydzielona często jest zwalniana dopiero wtedy, gdy klasa/moduł usuwane są z pamięci systemu podczas zamykania aplikacji (np. w sekcji finalization modułu).

Załóżmy np., że testujemy kod bazodanowy (MySQL via DBExpress). W teście tworzymy połączenie, wykonujemy operacje na danych i zwalniamy połączenie. Niestety, ponieważ DBExpress alokuje pamięć przy tworzeniu połączenia po raz pierwszy, i nie zwalnia jej dopóki aplikacja nie zakończy działania, otrzymujemy błąd przeciekania pamięci:
  procedure TYACDBTests.TestMemory;
  var
    LConnection: TSQLConnection;
  begin
    LConnection := CreateSQLConnection;
    Check(TRUE);
    FreeAndNIL(LConnection);
  end;
Kod jest w pełni poprawny (gdzie CreateSQLConnection tworzy obiekt, ustawia odpowiednia parametry i nawiązuje połączenie), ale nadal otrzymujemy informację o przeciekającej pamięci...

Jednym z możliwych rozwiązań jest dodanie kodu, który wymusiłby tę pierwszą alokację jeszcze przed uruchomieniem testów, aby w trakcie testów pamięć była już przydzielona (a więc i uwzględniona w obliczeniach zajętości pamięci przed testem).

Kod taki można umieścić np. w części inicjalizacyjnej modułu:
  var
    LConnection: TSQLConnection;
  initialization
    LConnection := CreateSQLConnection;
    FreeAndNIL(LConnection);
  end.
Teraz, gdy tworzymy połączenie TSQLConnection w teście, nie alokuje już ono więcej pamięci, zatem i DUnit nie raportuje przecieku... ;-)

Tego typu sytuacje są w miarę łatwo wykrywalne (choć nie w 100%) - gdy w pierwszym przebiegu DUnit zgłasza przeciek, ale przy drugim już nie (oba przebiegi wykonujemy podczas jednego uruchomienia programu DUnit). Wtedy mamy dużą szansę na to, że pamięć jest alokowana w pierwszym przebiegu, a w drugim jest już tylko wykorzystywana. I jest to dobry kandydat na rozwiązanie opisane powyżej, choć nie zawsze ustalenie, jaki kod należy uruchomić wcześniej, jest tak proste jak wyżej...

Góra

Komentarze
Kurczę!
Na razie brak komentarzy...

Góra

Dodaj komentarz (pola z gwiazdką są obowiązkowe)
Imię / ksywa *
Mail (pozostanie ukryty) *
Twoja strona
Komentarz (bez tagów) *
Wpisz tekst wyświetlony poniżej *
 

Góra

Tagi

Testowanie

Delphi


Podobne strony

AssertWasCalled a wielokrotne wywołania metod

AssertWas[Not]Called a właściwości obiektów

AssertWasNotCalled w Rhino Mocks

Visual Studio - przenoszenie testów UI do nowego / innego projektu skutkuje wyjątkami null reference

PrivateObject a parametry Out/ByRef

PrivateObject, WithEvents i uogólnienia

Interfejsy w Delphi... znowu

Dostęp do składowych prywatnych klas bazowych

PrivateObject a WithEvents

Dostęp do składowych prywatnych i chronionych - PrivateObject i PrivateType

VS - Test Run Error - "COM object that has been separated from its underlying RCW cannot be used"

Pobieranie kontrolki typu TreeViewItem dla elementów TreeView WPF

Output w testach MSTest (VS 2010)

Zautomatyzowane testy WPF a "Invalid URI: Invalid port specified."

Kontrola powiadamiania o zmianach wartości

Weryfikacja "wiszących" procedur obsługi zdarzeń w formach Delphi

AssertWasCalled w Rhino Mocks (w VB.NET)

Pierwsze kroki z Rhino Mocks (w VB.NET)

VS - testy w... toku

Przeciąganie plików na okno aplikacji

Intraweb a MaxConnections

Argumenty za używaniem FreeAndNIL

Intraweb jako moduł DSO Apache'a

Intraweb a "Device not supported"

Zautomatyzowane testowanie GUI

Zaokrąglanie i dokładność na FPU 8087

Intraweb a SessionTimeout

Używanie TChart w programach Intraweb

Unknown driver: MySQL

Zautomatyzowane testowanie GUI w maszynie wirtualnej

TIdMessage a CharSet

Gwarancje oprogramowania

Automatyczne testowanie formularzy okien

TChart - brakujące etykiety w osiach

Tracona pamięć i eksplozje połączeń w DBExpress

Kontrola dyrektyw kompilacji warunkowej oraz ustawień przełączników kompilacji

last_insert_id() a DBExpress

Rejestracja rozszerzeń

DBExpress a dostęp wielowątkowy

Formy jak ramki

Sprawdzanie błędnych odwołań a nowy menedżer pamięci

Dostęp do składowych chronionych

Obiekty, interfejsy i obsługa pamięci w Delphi - ki czort?