2009-07-29 8 views
20

Podczas pisania kodu w Javie, bardzo pomocne jest przyjmowanie composition i dependency injection, aby umożliwić i łatwo przeprowadzić test czystych jednostek poprzez kpiny ze współpracujących obiektów.Jak zrobić zastrzyk zależności i wyśmiewać w erlangu?

Uważam, że robienie tego samego w Erlang jest mniej proste i powoduje, że kod jest bardziej brudny.

To może być moja wina, bo jestem zupełnie nowy na Erlang i dość uzależniony JUnit, EasyMock i interfejsów Java ...

Powiedzmy mam tego głupiego funkcję:

%% module mymod 
handle_announce(Announce) -> 
    AnnounceDetails = details_db:fetch_details(Announce), 
    AnnounceStats = stats_db:fetch_stats(Announce), 
    {AnnounceDetails, AnnounceStats}. 

Kiedy testuję jednostkę mymod, chcę tylko udowodnić, że details_db i stats_db są wywoływane z właściwymi parametrami i że zwracane wartości są używane poprawnie. Zdolność details_db i stats_db do wygenerowania prawidłowej wartości jest testowana w innych miejscach.

Aby rozwiązać ten problem, mogę byłaby mój kod w ten sposób:

%% module mymod 
handle_announce(Announce, [DetailsDb, StatsDb]) -> 
    AnnounceDetails = DetailsDb:fetch_details(Announce), 
    AnnounceStats = StatsDb:fetch_stats(Announce), 
    {AnnounceDetails, AnnounceStats}. 

i przetestować go w ten sposób (w zasadzie stubbing połączenia bezpośrednio do modułu testowego):

%% module mymod_test 
handle_announce_test() -> 
    R = mymod:handle_announce({announce, a_value}, [?MODULE, ?MODULE, ?MODULE]), 
    ?assertEqual({details,stats}, R). 

fetch_details({announce, a_value}) -> 
    details. 

fetch_stats({announce, a_value}) -> 
    stats. 

To działa, ale kod aplikacji staje się brudny i zawsze muszę nosić tę paskudną listę modułów.

Próbowałem kilka bibliotek mock (erlymock i (this other one), ale nie był zadowolony.

jaki sposób jednostka przetestować swój kod erlang?

Dzięki!

Odpowiedz

22

Nie są dwie rzeczy do rozważenia tutaj ...

trzeba oddzielić cały swój kod do 2 różnych typów modułów:

  • pure moduły funkcjonalne (aka efektem ubocznym darmowe moduły)
  • Moduły z efektami ubocznymi

(należy zapoznać się na tym i upewnij się, że rozumiesz różnicę - najbardziej typowych stronie -effect - i ten, który jest w twoim próbnym kodzie - pisze do bazy danych).

Moduły, które są czysto funkcjonalne, stają się trywialne do przetestowania. Każda wyeksportowana funkcja (z definicji) zawsze zwraca te same wartości, gdy wprowadzane są te same wartości. Można użyć ramek EUnit/Assert, które napisali Richard Carlsson i Mickael Remond. Bish-bash-bosh, praca jest dobra "un ...

Najważniejsze jest to, że około 90% kodu powinno znajdować się w czystych modułach funkcjonalnych - dramatycznie zmniejszasz swój problem. (Można by pomyśleć, że to nie "rozwiązuje" twojego problemu, tylko "redukuje" go - i będziesz miał w większości rację ...)

Po uzyskaniu tego oddzielenia najlepszym sposobem na testowanie jednostek w modułach z efektami ubocznymi jest użycie standard test framework.

Sposób, w jaki to zrobić, aby nie używać makiety obiektów - ale załadowanie bazy danych w init_per_suite lub init_per_test funkcji, a następnie uruchomić moduły sami ...

Najlepszym sposobem jest poruszać się prosto do testy systemowe tak szybko, jak to tylko możliwe, ponieważ testy jednostek są trudne do utrzymania - wystarczająca liczba testów jednostkowych, aby przejść do testu systemowego w obie strony i nie więcej (jeszcze lepiej skasować testy jednostki db tak szybko, jak to możliwe) .

+0

Dzięki Gordon, bardzo dobrze wyjaśnione. Nadal próbuję przejść do paradygmatu funkcjonalnego. W każdym razie, w tym projekcie, który piszę (tracker tracker), wszystkie wywołania pochodzą z warstwy internetowej i kończą w bazie danych, więc większość modułów ma lub zależy od efektów ubocznych. Spróbuję standardowych ram testowych. –

+0

Dobry Erlang ma mieć wiele małych funkcji. Refaktor i włóż swój kod do modułów użytkowych, a będziesz zaskoczony, jak niewiele z tego wymaga zapisywania do bazy danych. 15 - 25 linii to długa funkcja w Erlang. Funkcja czysta to taka, która pobiera zestaw parametrów, oblicza na nich i po prostu zwraca wartość - powinieneś mieć ich dużo. –

+0

Nie zgadzam się, że powinieneś jak najszybciej przejść do testów integracyjnych. W przypadku sparametryzowanych modułów i szyderstw podanych przez erlymock, dana funkcja będzie trywialna do przetestowania. Możesz przetestować go wewnątrz samego modułu, kpiąc z dwóch modułów db na czas trwania testu. Możesz użyć tego modułu w innych testach, ustawiając moduły db jako parametry Twojego modułu. Każdy, kto patrzy na szyderczo w erlangu, powinien po raz drugi spojrzeć na erlymock - głównym problemem jest brak dokumentacji, więc naprawdę musisz przeczytać źródło, by pogodzić się z tym. –

4

Gordon ma rację, ponieważ głównym celem jest przetestowanie funkcji małych efektów ubocznych.

Ale ... cóż, możliwe jest również przetestowanie integracji, więc pokażemy, jak to zrobić.

Wtryskanie

Unikaj list do przenoszenia sparametryzowanych zależności. Użyj rekordu, słownika procesu, sparametryzowanych modułów. Kod będzie mniej brzydki.

Szwy

nie koncentrują się na zmiennych modułów jak szwy zależności, niech procesy być szwy. Zakodowanie zarejestrowanej nazwy procesu jest straconą szansą na wstrzyknięcie zależności.

+2

Nie polecam używania słownika procesu. Wszystko wydaje się łatwe i przyjemne, ale jest to WSPÓŁCZESNY STAN iw końcu będzie cię gryźć ciężko, aby znaleźć błędy. W Erlang bardzo trudno jest konceptualizować i zracjonalizować cykl życia procesu (choć można by pomyśleć, że potrafisz), a zmiana cyklu życia procesu polega na tym, że Twój słownik procesów czystych źle idzie. Znam to z gorzkiego doświadczenia :( –

+1

@Christian, link do emocka pojawia się martwy. Czy to samo: https://github.com/noss/emock? –

4

Po drugie, co mówi Guthrie. Będziesz zaskoczony, jak dużą część twojej logiki można wyciągnąć w czystych funkcjach.

Jedną z rzeczy, które ostatnio wiązałem z nowymi sparametryzowanymi modułami, jest użycie modułów paramterized do iniekcji zależności. Pozwala to uniknąć problemu z listami parametrów i słownikami procesów. Jeśli możesz użyć najnowszych wersji erlangu, które również mogą być dobre.

3

Po prostu odpowiadam na zadawane bezpośrednio pytanie i nie próbuję ocenić, czy autor powinien w ogóle to robić.

Korzystanie meck można napisać badanej jednostki dla Ciebie przykład w następujący sposób:

handle_announce_test() -> 
    %% Given 
    meck:new([details_db, stats_db]), 
    meck:expect(details_db, fetch_details, ["Announce"], "AnnounceDetails"), 
    meck:expect(stats_db, fetch_stats, ["Announce"], "AnnounceStats"), 
    %% When 
    Result = handle_announce("Announce"), 
    %% Then 
    ?assertMatch({"AnnounceDetails", "AnnounceStats"}, Result), 
    %% Cleanup 
    meck:unload(). 

używam strun tylko naciskiem, że nie są one czymś, co jest przekazywane w bardzo, ale raczej fałszywe wartości. Dzięki podświetleniu składni są łatwe do wykrycia w kodzie testowym.

Szczerze mówiąc jestem byłym programistą Java, głęboko zakochanym w Mockito, który niedawno przeszedł na Erlang, a teraz wnosi wkład w wyżej wymieniony projekt.

Powiązane problemy