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