Tag: tests

Błąd “Errno::EMFILE: Too many open files” w testach jednostkowych

Dzisiaj pisząc kolejną porcję testów do Senpuu v5, po odpaleniu ich pod RCovem i Rubym 1.8.7 napotkałem na taki oto błąd:

Errno::EMFILE: Too many open files

Błąd ten związany jest z ilością otwartych jednocześnie plików (co ciekawe nie wystąpił podczas odpalania testów pod 1.9.2). Okazuje się, że tego typu wywołania:

file = File.new(File.join(Rails.root, "sciezka/do/pliku"), 'rb')

nie są nigdy zamykane, więc otwierając przykładowo 100 plików, żaden z nich nigdy nie zostanie zamknięty (przy zamykaniu aplikacji zostana). Z czasem ilość otwartych plików narasta i po pewnym czasie następuje zgłoszenie wyżej wspomnianego wyjątku. Rozwiązanie jest nader proste: zamykajmy otwierane pliki :)

W przypadku aplikacji jest to dość proste (robimy coś na pliku, kończymy i zamykamy). Jak jednak zapanować nad otwartymi plikami w testach? Przyznam szczerze, że jestem zbyt dużym leniem aby pamiętać o zamykaniu każdego pliku otworzonego w każdym teście. Z tego względu warto zbudować sobie prosty garbage collector który zajmie się tym za nas. Jak to zrobić pokaże na przykładzie podpięcia takiego kodu pod ActiveSupport::TestCase. Nic nie stoi na przeszkodzie aby tę metodę stosować także dla innych frameworków jak np. RSpec.

W metodze setup deklarujemy zmienną instancyjną, która przechowywać będzie nasze otwarte pliki:

  def setup
    super
    # Jakis inny kod ...
    @opened_files = []
  end

W metodzie teardown zamykamy wszystko:

  def teardown
    super
    # Jakis inny kod
    @opened_files.each { |f| f.close }
  end

I ostatnia z metod - metoda otwierająca pliki i zapamiętująca je w naszej zmiennej:

  def open_file(file = nil)
    return nil if filename.nil?
    file = File.new(File.join(Rails.root, file), 'rb')
    @opened_files << file
    file
  end

Od teraz, korzystając z metody open_file nie musimy się martwić otwartymi plikami. Zostaną automatycznie zamknięte podczas wywołania metody teardown.

Rails 3 + Errors#on have been deprecated, use Errors#[] instead

Probably you have already noticed that, but in Rails 3 got some new stuff going on. Same goes when testing Rails applications. Using errors.in(:key) is now deprecated so you'll probably need to change a whole bunch of tests and assertions. However, there is a quite fast way to do it. Open project in Netbeans and use Replace in project.

Go to Edit --> Replace in projects and type into corresponding fields:

Containing text: errors.on\((.+)\)\,
Replace With: errors\[$1\].first\,

Select "regular expression" and press find. Wait few seconds for the results and press replace.

After that rerun your tests:

rake test:all
# or if rspec
rake spec

Copyright © 2024 Closer to Code

Theme by Anders NorenUp ↑