2008-12-20 15 views
17

Spędzam trochę czasu z Erlangiem i chcę zastosować TDD do kodu, który piszę.Jaki jest najlepszy sposób na równoczesny test kodu jednostki Erlang?

Podczas gdy EUnit w standardowej bibliotece udostępnia przyjemną, tradycyjną platformę testową do testowania zwykłego kodu, nie wydaje się, aby było cokolwiek, co mogłoby pomóc w testowaniu współbieżnego kodu, który jest używany w LOT w Erlang.

Należy zauważyć, że mówimy tu o Erlangu, który wykorzystuje przekazywanie komunikatów (w przeciwieństwie do stanu współdzielonego) do komunikacji między procesami współbieżnymi, więc techniki testowania kodu współbieżnego w udostępnionych kodach w językach z opcją współdzielenia mogą nie mieć zastosowania.

Ktoś znalazł dobry sposób na przetestowanie równoległego kodu w Erlangu?

Odpowiedz

1

Ponieważ błędy w kodzie współbieżnym objawiają się w zależności od kolejności wykonania różnych części, myślę, że najlepiej jest nie polegać na testach, aby wykryć błędy w równoczesnej części kodu. Takie błędy są bardzo łatwe do przeskoczenia i niezwykle trudne do zlokalizowania. Zobacz na przykład, jak technika podwójnego blokowania, która była powszechnie cytowana i używana jako skuteczna metoda wdrażania leniwej inicjalizacji w środowisku wielowątkowym, was later found to be broken. Znacznie lepiej jest używać odpowiednich abstrakcji i technik, aby współbieżne części kodu były "poprawne".

+0

Ta rada odnosi się do języka takiego jak Java z współdzieloną współbieżnością stanu. Jednak Erlang używa przekazywania komunikatów i masz kontrolę nad tym, kiedy dane są wysyłane do innych procesów iw jakiej kolejności są odbierane. Zasadniczo więcej kontroli. Wydaje się, że powinny istnieć kod/wzorce testowe. – madlep

+0

To prawda, że ​​brak współdzielonego stanu pozwala uniknąć problemów związanych z uszkodzeniem danych lub niespójnością. Ale nadal musisz martwić się synchronizacją. Mam rację? –

0

Dodając do tego, co powiedział Diomidis, jedynym prawdziwym sposobem na uzyskanie pewności siebie w związku z kodem współbieżnym jest przeprowadzenie rozszerzonych testów w stale zmieniających się warunkach; i nawet wtedy jest to tylko dowód, że nie zawiódł w tych warunkach.

2

Jedno narzędzie wiem, że można używać do testowania programów Erlang pod jednoczesnych scenariuszy jest QuickCheck: http://www.quviq.com/

można określić oczekiwane zachowanie używając właściwości, a narzędzie może wykonywać swój program Erlang w pewnym zakresie dane wejściowe i czas, aby upewnić się, że właściwości są spełnione.

Niestety jest to narzędzie komercyjne

mają również do obejrzenia projektu Protest: http://www.protest-project.eu

Aktualizacja: Projekt protest opublikowali badanie, "Results for: Erlang testing tools survey for the ProTest project"

5

Pytanie jest nieco niejasne ("Erlang jest równoczesny, przetestuj go z Erlangiem!"), Ale postaram się trochę rozwinąć.

Testowanie kodu Erlang może się wahać od prostego prostego (prawe wejście tworzy właściwe wyjście) do konfigurowania złożonych wiązek testowych, które sprawdzają, czy komponent zachowuje się tak, jak powinien. To, co jest najlepsze w danej sytuacji, zależy całkowicie od wymagań, które posiadasz, oraz od ilości testów czarnych skrzynek/białych skrzynek, które chcesz wykonać.

Częścią piękna Erlanga jest możliwość przejrzystego współbieżności.Rozważmy następujący przykład (funkcję parallelizes zbiorcze listy list):

deep_sum(ListOfLists) -> 
    Parent = self(), 
    [spawn(fun() -> Parent ! lists:sum(List) end) || List <- ListOfLists], 
    lists:sum([receive Sum -> Sum end || _ <- ListOfLists]). 

Będziesz zwykle przetestować to z bardzo prostego testu EUnit:

deep_sum_test() -> 
    ?assertEqual(0, deep_sum([0, 0, 0, 0])), 
    ?assertEqual(40, deep_sum([10, 10, 10, 10]). 

Teraz, powiedzmy, że mają nieco bardziej wyraźny API do tego funkcjonalność: basen proces jako argumentu:

deep_sum(Pool, ListOfLists) -> 
    distribute_lists(Pool, ListOfLists), 
    lists:sum([receive Sum -> Sum end || _ <- ListOfLists]). 

distribute_lists(Pool, ListOfLists) -> distribute_lists(Pool, Pool, ListOfLists). 

distribute_lists([P|Pool], All, [L|ListOfLists]) -> 
    P ! {self(), L}, 
    distribute_lists(Pool, All, ListOfLists); 
distribute_lists([], All, ListOfLists) -> 
    distribute_lists(All, All, ListOfLists); 
distribute_lists(_Pool, _All, []) -> 
    ok. 

testując to mamy do czynienia z fałszowanie tej puli procesów:

deep_sum_test() -> 
    Pool = [spawn_link(fun() -> fake_pool(1) end) || _ <- lists:seq(1, 3)], 
    ?assertEqual(4, deep_sum(Pool, [lists:seq(1, 3) || _ <- list:seq(1, 4)]), 
    ?assertEqual(7, deep_sum(Pool, [lists:seq(1, 3) || _ <- list:seq(1, 7)]), 
    [P ! stop || P <- Pool]. 

fake_pool(CannedResponse) -> 
    receive 
     {From, _L} -> From ! CannedResponse; 
     stop -> ok 
    end, 
    fake_pool(CannedResponse). 

Jak widać, testowanie programów współbieżnych w Erlang może przybierać różne kształty. Są to bardzo proste przykłady, ale dzięki wbudowanym prymitywom współbieżnym Erlanga bardzo łatwo jest stworzyć rodzaj uprzęży testowej, którą chcesz, i abstrakty na właściwych poziomach.

Zwykle stwierdzam, że TDD jest ortogonalny, aby testować kod współbieżny, a więc te techniki testowania mogą być również używane do normalnych testów jednostkowych.

9

Właśnie znalazłem całkiem fajne nowo opracowane oprogramowanie (do 2011 r.) Do testowania współbieżnych aplikacji Erlang o nazwie Concuerror. Jest na nim fewpapers i repository on github. Wygląda na to, że działa za pomocą własnego harmonogramu i systematycznie testuje różne przeplatanie między procesami.

Warto również wspomnieć dializatora (rozbieżność analizator Erlang) (Papers, Tutorial, Manual), który jest narzędziem do analizy statycznej kodu do znalezienia błędów. To ma również wsparcie dla wykrywania niektórych błędów współbieżności (patrz paper).

Nie testowałem żadnego z nich samodzielnie, chociaż dializator wydaje się być stosunkowo dojrzałym oprogramowaniem. Oba programy mają GUI do pracy z testami.

PS. W przypadku nie łączących się części, EUnit i QuickCheck (istnieje również wersja bezpłatna) powinny działać poprawnie.