Tag: RoR

RVM + naprzemienne korzystanie z 1.8.7 i 1.9.2 – czyli jak stracić 2 godziny z życia

Jeśli chcecie stracić 2 godziny z życia, to mam dla Was świetny sposób. Róbcie migracje pod 1.8.7 a testujcie i odpalajcie serwer pod 1.9.2 ;)

Wczoraj pracowałem nad pewnym kawałkiem kodu, dla którego dużo łatwiej jest robić:

rake db:migrate VERSION=0

niż tworzyć nowe migracje.

Z tego względu, jak nietrudno zauważyć, często zmieniały mi się takie dane jak np hash dla hasła. Nie byłoby w tym nic specjalnego, gdyby nie to, że mam dość mocno "zakorzeniony" w Rubym sposób generowania hasha. Był on zależny od pewnych metod w Rubym, w taki sposób, że po zmanie sposobu obsługi charów i stringów w 1.9.2, także on uległ zmianie. Skutkiem tego było to, że wynikowy hash generowany przez tą samą metodę w drzewie 1.8 i 1.9 różnił się znacząco.

Ta różnica, skutkowała tym, że nie dało się zalogować na konto usera. Oczywiście zanim dotarłem do przyczyny, minęły wyżej wspomniane 2 godziny.

Nie radzę Wam, bawić się jednocześnie 1.8.7 i 1.9.2, a jeśli już musicie i coś przestanie działać, to w pierwszej kolejności odpalcie wszystko tylko pod jedną z tych dwóch wersji.

Jak to RCov z Rails3 i Rubym 1.9.2 przestał działać (i jak temu zaradzić)

Po przesiadce na Rails 3.0.0 i nowego Rubiego 1.9.2, okazało się że RCov nie działa (tzn. działa ale wyniki jakie przedstawia są "lekko" niewłaściwe). Zresztą, zapuszczając RCova dostajemy taką oto wiadomość:

** WARNING: Ruby 1.9 Support is experimental at best. Don't expect correct results! **

Dodatkowo rcov mimo podawania konkretnych plików, sam zaczął testować także gemy i masę innego kodu.

Jak temu zaradzić?
Niezgodność z Rubym 1.9.2 naprawić można stosunkowo prosto. Trzeba po prostu... wrócić do Rubiego 1.8.7 :)

Dzięki skorzystaniu z RVM (Ruby Versiom Manager), jest to bardzo proste. Instalujemy RVM, zmieniamy wersję Rubiego i już.

Pozostaje jednak jeszcze jeden dziwny problem. Z jakiegoś powodu pliki nie chcą ładować się z automatu tylko trzeba każdy z nich wywołać ręcznie za pomocą polecenia:

ruby sciezka_do_pliku/plik.rb sciezka_do_plku2/plik2.rb

Ten problem rozwiązałem, pisząc sobie prosty skrypt który "zbiera" mi pliki, które mam przetestować. Następnie odpala RCova poleceniem system, podając jako parametry wszystkie pliki na których ma RCov działać. Opiszę ten kod w miarę dokładnie, a następnie pokażę sposób użycia.

Pierwszą rzeczą jaką trzeba zrobić, jest zadeklarowanie jakich bibliotek nam potrzeba, oraz zdefiniowanie tych katalogów, w których mamy nie szukać plików *.rb:

# coding: utf-8
require 'find'
require 'fileutils'

EXCLUDED = ['.svn', 'fixtures', 'additional_data', 'coverage', 'integration', 'performance']

jak więc widać, nie będziemy przeprowadzać testów integracyjnych oraz wydajnościowych. Pominiemy także repo svna i inne niepotrzebne katalogi.

Aby sprawdzić czy ścieżka którą chcemy odpytać jest ścieżką niedozwoloną, tworzymy taką metodę:

# Czy dana ścieżka nie należy do sciezek z testami
def excluded?(path)
  EXCLUDED.each{ |ex|
    return true if path.include?(ex)
  }
  return false
end

Następnie musimy stworzyć metodę, która będzie nam zwracała ilość plików *.rb w katalogu w którym jesteśmy (aby nie podawać ścieżek bez plików do RCova):

def file_nr(path)
  all = Dir.open(path).collect
  file_nr = 0
  all.each { |f|
    file_nr += 1 if !File.directory?("#{path}/#{f}") && File.exists?("#{path}/#{f}")
  }
  file_nr
end

Przyjęliśmy tutaj założenie że w katalogach z których zbieramy, nie ma plików innych niż *.rb.

Kolejna metodą której będziemy potrzebować, jest metoda przygotowująca nam z tablicy ścieżek, jednego stringa o wzorze:

katalog/*.rb katalo2/*.rb ... katalonN/*.rb

Metoda ta zbiera ścieżki i dodaje do nich *.rb:

def prepare_params(paths)
  paths.collect! { |d| d + '/*.rb'}
  params = ''
  paths.each{ |d| params += " #{d}"}
  params
end

Teraz nie pozostaje nam nic innego, jak tylko "przelecieć" katalog test/, powyciągać to co trzeba i odpalić Rcova:

helpers = []
functional = []
unit = []
# Pobierzmy listę katalogów w /test
Find.find(path = './test/'){ |f|
  if File.directory?(f) && !excluded?(f) && file_nr(f) > 0
    # Rozdzielamy testy helperow, unitow i functionals
    if f.include?('helpers')
      helpers << f
      next
    end

    if f.include?('functional')
      functional << f
      next
    end

    if f.include?('unit')
      unit << f
      next
    end

  end

}
# #{prepare_params(helpers)}
system "rcov #{prepare_params(unit)} #{prepare_params(functional)} -o ./test/coverage/ --exclude gems --exclude boot.rb"

Kod ten wrzucamy do katalogu script, a uruchamiamy wpisując:

# Zakladamy ze jestesmy w katalogu głownym aplikacji (Rails.root)
ruby script/rcov.rb

Warto pamiętać że RCov działający na 1.8.7, ale testujący kod pisany pod 1.9.2, niekoniecznie zrealizuje poprawnie wszystkie testy. Część testów (u mnie około 1%) nie zadziała. Winą za to można obarczyć chociażby to że 1.8.7 nie ma metody cover?, z której ja dość często korzystam. Nie stanowi to jednak problemu jeśli z RCova korzystamy poglądowo a do testów właściwych wykorzystujemy rake test.

Plik z gotowym kodem, do pobrania tutaj: rcov_runner

Copyright © 2025 Closer to Code

Theme by Anders NorenUp ↑