Jednak dla mnie pytanie wskazywało raczej potrzebę zrozumienia, jak to jest testować aplikacje Clojure w Clojure. Trafiłem na clojure.contrib.test-is, gdzie znalazłem informację, że teraz Clojure oferuje clojure.test.
Sprawdźmy, jak to działa. Krótko.
devmac:~ jacek$ clj Clojure 1.2.0 user=> (use 'clojure.test) nil user=> ; Czy 5 == 4? user=> (is (= 5 (+ 2 2))) FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:5) expected: (= 5 (+ 2 2)) actual: (not (= 5 4)) false user=> ; Test mianowany "Crazy arithmetic" user=> (is (= 5 (+ 2 2)) "Crazy arithmetic") FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:6) Crazy arithmetic expected: (= 5 (+ 2 2)) actual: (not (= 5 4)) false user=> ; Można również definiować zestawy testowe makrem deftest user=> (deftest addition (is (= 4 (+ 2 2))) (is (= 7 (+ 3 4)))) #'user/addition user=> ; ...i je uruchamiać funkcją run-tests user=> (run-tests) Testing user Ran 1 tests containing 2 assertions. 0 failures, 0 errors. {:type :summary, :test 1, :pass 2, :fail 0, :error 0}Można też uruchomić testy z innej przestrzeni nazewniczej (aka pakietach w Clojure). W ten sposób oddzielamy sam test od testowanego kodu.
user=> ; Definiujemy nową przestrzeń testy user=> (ns testy) nil testy=> (use 'clojure.test) nil testy=> ; W niej definiujemy zestaw testowy makrem deftest testy=> (deftest addition (is (= 7 (+ 3 4)))) #'testy/addition testy=> ; Zmieniamy aktualną przestrzeń testy=> (ns user) nil user=> ; Wykonujemy testy z innej przestrzeni user=> (run-tests 'testy) Testing testy Ran 1 tests containing 1 assertions. 0 failures, 0 errors. {:type :summary, :test 1, :pass 1, :fail 0, :error 0}p.s. Wczoraj wyszła wersja Clojure 1.3 Alpha 2, ale poza tym, że jest i podobno jest ciekawa, nic więcej :)
Kod funkcyjny testuje sie bardzo fajnie za pomoca prostych algebraicznych wlasciwosci, ktorych spelnienie sie sprawdza (w przyblizeniu oczywiscie) za pomoca testow probabilistycznych.
OdpowiedzUsuńPrzykladem takiej biblioteki jest ScalaCheck:
http://code.google.com/p/scalacheck/
Uzywam jej z powodzeniem w swoich projektach i uwazam, ze istnieje bardzo duza klasa problemow gdzie sprawdza sie znacznie lepiej niz jakikolwiek framework do testowania znany z Javy.
Początkowo przejrzałem stronę domową SC z pewnym powątpiewaniem i nie bardzo mogłem zrozumieć, co w tym takiego odkrywczego. Dopiero przeczytanie artykułów (patrz ScalaCheck Articles, a dokładnie tego pierwszego Tony Morris - Automated Unit Testing your Java using ScalaCheck) dało mi pogląd na ten temat.
OdpowiedzUsuńTo jest obowiązkowe narzędzie, które od dzisiaj znajduje swoje miejsce w moim warsztacie programistycznym.
Jak to ujął autor wspomnianego artykułu - w JUnit i temu podobnych testujemy prawdziwość naszych warunków, których liczba i dane zależą od chęci i pomysłowości autora. W ScalaCheck dane są generowane automatycznie, a my jedynie określamy warunki jakie musi spełniać nasz typ. Wspaniałe!
Już tym ujął mnie za serce, ale kiedy padło magiczne słowo monada (w Luckily, generators are instances of what is known as a functor (also, a monad), so this task will be quite trivial.) przypomniałem sobie, że u tego Pana już kiedyś byłem - poznałem te lambdy w tytule jego bloga.
Jest to kolejny przykład, że zabranie się za języki funkcyjne, pozwoliło mi na poszerzenie zestawu narzędzi, którymi operuję, a monady mają coś, czego bez Clojure na pewno bym nie dotknął.
Dzięki Grześ!
Zatem ClojureCheck [http://kotka.de/blog/2010/06/ClojureCheck_is_back.html] może też Ci się spodobać :)
OdpowiedzUsuń