Showing posts with label phantomjs. Show all posts
Showing posts with label phantomjs. Show all posts

Thursday, November 17, 2011

PhantomJS i Ruby - czyli przygody małe i duże

No więc stało się. Jestem programistą Javy. I co z tego? A no trzeba w domu jakoś odreagować.
Na pierwszy ogień poszedł Ruby i to nie byle jaki jak 1.9.3-p0. Windowsowa paczuszka ściągnięta wprost z RubyInstaller ślicznie zadomowiła się w moim systemie operacyjnym, dając mi nawet w trakcie instalacji dodać poleceni ruby do ścieżki systemowej.

No ale nie o Rube-go chodzi tylko o chęć napisania jakiegoś drobiazgu z meta-programowaniem. No więc potrzebny jest edytor.

gem install redcar
redcar install
redcar
I moim pięknym oczom ukazał się turbo edytor RedCar - i od razu zrezygnowałem nawet z myśli o płaceniu za TextMate na Mac-u. Napisałem sobie bardzo prosty program, który pozwolę sobie dumnie nazwać klient "REST". Tak naprawdę to prawie na jedno by wyszło jakby podziedziczył po Net::HTTP, ale że miało być "meta-programowanie" to wyszło tak:


require 'net/http'
require 'uri'

class REST
def self.method_missing(m, *args, &block)
uri = URI(args[0])
Net::HTTP.start(uri.host, uri.port) do |http|
puts "Calling #{m} REST call."
return http.send(m.downcase.to_sym, uri.path)
end
end
end

res = REST.GET("http://www.google.pl/")
puts res.body


Nikt, nie mówił, że jest się czym chwalić, ale coś mnie tchnęło, żeby pobrać (a co) zawartość wyżej wymienionej strony w PhantomJS. Trwa to wieki i gdyby tak działała przeglądarka to pewnie zrezygnowałbym z Internetu, albo kazał, za korzystanie z niego, sobie płacić, ale ... na szczęście Google Chrome ładuje WebKit raz a nie za każdym razem gdy otwieram zakładkę - więc da się żyć. Na stronie projektu, gdy napisałem już skrypt w JavaScript zauważyłem, że mogę też podawać skrypty w CoffeeScript pominę więc moje wypociny w JS i podam odrazu wersję Coffee, a jak interesuje Cię co napisałem w JS to wklej sobie poniższą zawartość na stronie Try CoffeeScript i będziesz wiedział.

page = new WebPage()

if phantom.args.length == 0
console.log 'Usage: google.coffee some-url'
phantom.exit()
else
t = Date.now()
address = phantom.args[0]
page.open address, (status) ->
if status != 'success'
console.log 'FAIL to load the address'
else
t = Date.now() - t
console.log 'Loading time ' + t + ' msec'
console.log 'Page content is \n' + page.evaluate () ->
document.documentElement.innerHTML
phantom.exit()


Edytor kodu na Blogger jak zwykle daje ciała nie wspierając wstawek kodu źródłowego, ale co tam. Najgorsze, że RedCar nie ma wsparcia dla CoffeeScript, ale może się dorobi jak skończy być Alphą. No nic, czas kończyć. Na dziś starczy już tego dobrego wracamy do Thinking in Java, którego autor i tak co 100 zdanień kończy stwierdzeniem w stylu "Java to ogromny krok na drodze postępu w tej dziedzinie, ale Python i tak robi to lepiej."

P.S. Moim ogromnym odkryciem w Ruby było odkrycie, że każdy operator to metoda. Kiedyś nie mogłem znaleźć w dokumentacji co dokładnie robi ~= (czy tam =~) bo szukałem jakiegoś działu dokumentacji Ruby-Doc, który definiowałby operatory zamiast sprawdzić metodę =~ klasy String albo RegExp.

Friday, May 27, 2011

Webdevelopment i unit testy

Kilka tygodni temu zacząłem developować webowy frontend dla projektu gitolite o nazwie glboard. Gitolite to warstwa abstrakcji pozwalająca na kontrolę dostępu do repozytoriów systemu git podczas dostępu do serwera przez ssh.

Glboard od samego początku pisany był z myślą o testach, dlatego wraz z kodem publikowane były unit testy do udowadniania poprawności metod, klasy, która stanowi trzon funkcjonalności.
Podczas oglądania prelekcji "State of Pylons/Turbo Gears2/repoze.bfg", moją uwagę przykuły zarzuty postawione unit testom w web-developmencie.

W tym okresie spędziłem sporo czasu, w glboard, na poprawianiu unit testów. Jeżeli padłem ofiarą zbyt wczesnego testowania - to jaki sens ma Test Driven Development?
Podczas zmieniania głównej klasy, obsługującej operacje na repozytorium gita, uzyskałem pewien ciekawy efekt - witryna działała i mogłem dzięki niej wykonać wszystkie operacje - natomiast testy failowały. Wszystkie. Powód był prosty: klasa przyjmowała teraz nowy argument w metodzie __init__.

Wspomniana prelekcja uświadomiła mi jedną rzecz. Jeżeli nie wystawiasz czegoś na zewnątrz, nie wystawiasz API lub biblioteki, nie będziesz zobligowany do zachowywania wstecznej kompatybilności z jakimś stworzonym przez siebie interfejsem, które kiedyś udostępniłeś, tylko dlatego, że używają go klienci - nie używaj unit testów. Pisanie unit testów do elementów, które zostają w twoim projekcie i nie wychodzą w żaden sposób na zewnątrz - to strzelanie sobie w stopę.

Moim zdaniem pisząc aplikację we frameworku webowym to co powinno się testować - to działanie przez przeglądarce. Testy funkcjonalne wydają się wystarczające. Może są troszkę bardziej kosztowne niż unit testy, ale w gruncie rzeczy, dobrze napisane, testują dokładnie to co powinny. Nie skupiają się na API konkretnej klasy, funkcji, metody, ale na tym czy witryna działa - nie ważne jest jak.

Odnosząc się do narzekań na Selenium i długiego czasu trwania testów w nim napisanych: myślę, że możemy spodziewać się rewolucji w świecie testów web-aplikacji dzięki PhantomJS. Nie znam jego wydajności, ale funkcjonalność jest w tej dziedzinie bardzo obiecująca i daje znacznie więcej możliwości niż zwykłe funkcyjne testy. Równocześnie nie używa całego niepotrzebne osprzętu jakie ładuje przeglądarka.

Wszystko co w tej chwili mi pozostaje to usunąć unit testy z glboard i napisać functional testy :)