Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

Godny następca C i C++, czyli programowanie w D - cz. 4: Kontrakty i testy jednostkowe

Było o tym, czym jest D. Było też o kompilacji warunkowej i tablicach. Teraz pokażę trochę ważniejszą cechę języka D - programowanie kontraktowe.

Programowanie kontraktowe jest techniką polegającym na umieszczaniu w źródłach programu kodu sprawdzającego poprawność jego działania. W przypadku wykrycia nieprawidłowości program wymusi tzw. crash i zakończy działanie, aby nie doprowadzić do zwrócenia błędnego wyniku.

Asercje

Za najprostszy rodzaj kontraktów można uznać asercje. Są one dostępne w innych językach programowania, takich jak C, C++ i Java. W D stosuje się je tak:assert(2 == 1); Po uruchomieniu programu z tym kodem zostanie wyrzucony wyjątek AssertError. Gdy kompilatorowi przekażemy flagę -release, asercja powinna zostać pominięta przy kompilacji i nie znaleźć się w programie. Niestety do kompilatora prawdopodobnie wkradł się błąd, ponieważ przy próbie uruchomienia tego kodu:import std.stdio; void main() { assert(1 == 2); writeln("Hello World"); } skompilowanego z flagą -release otrzymałem błąd Segmentation fault. Prawdopodobnie jest to regresja, ponieważ kiedyś już testowałem asercje i działały poprawnie.

Kontrakty wejściowe i wyjściowe, testy jednostkowe

Kontrakty możemy też umieszczać przy funkcjach. Będą one wtedy sprawdzać poprawność danych wejściowych funkcji oraz jej wyniku. Dzięki temu możemy się upewnić, że dane przyjmowane przez funkcje są zgodne z jej wymaganiami oraz że jej wynik spełnia określone kryteria. import std.stdio; import std.string; string trim(string s) out(res) { assert(res.length == 0); // 10.05 -> poprawiłem literówkę. } body { int i = 0; for(; i = 0; j--) { if(!iswhite(s[j])) { break; } } if(i > j) { return ""; } else { return s[i..j+1]; } } unittest { assert(trim("string") == "string"); assert(trim(" string") == "string"); assert(trim("string ") == "string"); assert(trim(" string ") == "string"); assert(trim("str ing") == "str ing"); assert(trim(" str ing") == "str ing"); assert(trim("str ing ") == "str ing"); assert(trim(" str ing ") == "str ing"); assert(trim("") == ""); } void main() { writeln(trim(" Hello World! ")); }Zamiast zwykłego bloku funkcja z kontraktami ma taką postać:char[] usunbiale(char[] x) in { ... // W przykładzie powyżej ten kontrakt został pominięty. } out(res) { ... } body { ... } unittest { ... } Możemy wyróżnić 4 bloki:
- in - odpowiada za sprawdzanie, czy argumenty funkcji są poprawne. Należy pamiętać, że po kompilacji z parametrem -release blok zostanie pominięty, więc nie powinien być wykorzystywany do sprawdzania danych wprowadzonych przez użytkownika.
- out - sprawdza, czy wynik działania funkcji spełnia określone wytyczne. W przykładzie funkcji usuwającej białe znaki z początku i końca ciągu znaków blok out sprawdza np., czy ciąg po usunięciu białych znaków nie jest dłuższy od wyjściowego - gdyby tak było, świadczyłoby to o błędnym działaniu funkcji.
- body - w tym bloku zawarta jest właściwa funkcja.
- unittest - są to tzw. testy jednostkowe. Wykonywane są one zaraz po uruchomieniu programu, ale przed przejściem do metody main. W przykładzie w bloku unittest wielokrotnie wywołano funkcję dla niektórych przypadków i upewnia się, że jej wynik jest poprawny. Testy jednostkowe przydają się do sprawdzenia "skrajnych" przypadków, które przez przypadek mogliśmy pominąć (np. usuwanie białych znaków z ciągu, w którym są tylko białe znaki lub z pustego ciągu). Aby wkompilować testy jednostkowe do programu, należy użyć flagi kompilatora -unittest.

Bloki in i out muszą znaleźć się przed blokiem body w kodzie, zaś unittest za nim.

Testy jednostkowe są również dostępne w innych językach za pomocą odpowiednich bibliotek. D jednak wbudowuje je razem z kontraktami w język, dzięki czemu są one lepiej zintegrowane, czytelniejsze i prostsze w użyciu.

Programowanie kontraktowe jest bardzo dobrym rozwiązaniem pomagającym wykrywać błędy, które przeoczyliśmy w trakcie pisania kodu. Wielka szkoda, że - jak na ironię - do języka D błąd wkradł się właśnie w asercje. Miejmy nadzieję, że twórcy jak najszybciej go usuną.

A w kolejnej części...

To już czwarta część cyklu wpisów o D na moim blogu. Czy pojawi się piąta? Prawdopodobnie tak, ale nie wiem jeszcze, o czym dokładnie będzie. Zapraszam do śledzenia bloga. 

Komentarze

0 nowych
bart86   10 #1 10.04.2010 21:52

tyle wiesz o D że mógłbyś założyć stronę internetową z kursem tego języka popularność języka C++ wydaje mi się zaczyna od łatwo dostępnych kursów, blogów w internecie oraz porad na forach w naszym rodzimym języku oczywiście nie to decyduje o popularności danego języka programowania ale jest tego dobrym fundamentem

borzole   4 #2 10.04.2010 22:39

dałbyś jakieś obrazki, to zawsze ożywia wpis ;)

  #3 11.04.2010 00:09

świetny kurs... oby tak dalej ;)

Mi2   4 #4 11.04.2010 13:33

bart86 - Kurs od podstaw można znaleźć na Wikibooks: http://pl.wikibooks.org/wiki/D . Nie jest do końca aktualny, ponieważ niektóre fragmenty pisane są pod D 1.0, niektóre pod 2.0 i to jest troszkę pomieszane. Może kiedyś pomyślę, żeby zrobić tam porządek i trochę dopisać. Na razie nie mam zbyt wiele czasu, bo poza tymi wpisami piszę jeszcze komunikator właśnie w D ;)

A te wpisy kieruję do tych, którzy już znają przynajmniej podstawy programowania. Chcę pokazać, czym jest D, a nie czym jest programowanie. Nie zmieściłbym kursu od podstaw w kilku wpisach.

borzole - być może w jednym z kolejnych wpisów zajmę się GUI, to będzie więcej obrazków. Programowanie kontraktowe trudno narysować ;)

borzole   4 #5 11.04.2010 13:53

@Mi2
to chociaż daj jakiś schemat do pokolorowania :)