簡體   English   中英

如何使用Ruby RSpec對“磁盤已滿”方案進行單元測試?

[英]How to unit test a “disk full” scenario with Ruby RSpec?

我需要單元測試場景,如下所示:

磁盤有1MB的可用空間。 我嘗試將2MB的文件復制到磁盤上。

使用Ruby RSpec執行此操作的最佳方法是什么?

有關詳細信息,我需要對以下文件緩存方法進行單元測試,因為它似乎有一些問題:

def set first_key, second_key='', files=[]
  # If cache exists already, overwrite it.
  content_dir = get first_key, second_key
  second_key_file = nil

  begin
    if (content_dir.nil?)

      # Check the size of cache, and evict entries if too large
      check_cache_size if (rand(100) < check_size_percent)

      # Make sure cache dir doesn't exist already
      first_cache_dir = File.join(dir, first_key)
      if (File.exist?first_cache_dir)
        raise "BuildCache directory #{first_cache_dir} should be a directory" unless File.directory?(first_cache_dir)
      else
        FileUtils.mkpath(first_cache_dir)
      end
      num_second_dirs = Dir[first_cache_dir + '/*'].length
      cache_dir = File.join(first_cache_dir, num_second_dirs.to_s)
      # If cache directory already exists, then a directory must have been evicted here, so we pick another name
      while File.directory?cache_dir
        cache_dir = File.join(first_cache_dir, rand(num_second_dirs).to_s)
      end
      content_dir = File.join(cache_dir, '/content')
      FileUtils.mkpath(content_dir)

      # Create 'last_used' file
      last_used_filename = File.join(cache_dir, 'last_used')
      FileUtils.touch last_used_filename
      FileUtils.chmod(permissions, last_used_filename)

      # Copy second key
      second_key_file = File.open(cache_dir + '/second_key', 'w+')
      second_key_file.flock(File::LOCK_EX)
      second_key_file.write(second_key)

    else
      log "overwriting cache #{content_dir}"

      FileUtils.touch content_dir + '/../last_used'
      second_key_file = File.open(content_dir + '/../second_key', 'r')
      second_key_file.flock(File::LOCK_EX)
      # Clear any existing files out of cache directory
      FileUtils.rm_rf(content_dir + '/.')
    end

    # Copy files into content_dir
    files.each do |filename|
      FileUtils.cp(filename, content_dir)
    end
    FileUtils.chmod(permissions, Dir[content_dir + '/*'])

    # Release the lock
    second_key_file.close
    return content_dir
  rescue => e
    # Something went wrong, like a full disk or some other error.
    # Delete any work so we don't leave cache in corrupted state
    unless content_dir.nil?
      # Delete parent of content directory
      FileUtils.rm_rf(File.expand_path('..', content_dir))
    end
    log "ERROR: Could not set cache entry. #{e.to_s}"
    return 'ERROR: !NOT CACHED!'
  end

end

一種解決方案是存根寫入磁盤以引發錯誤的方法。 例如,對於測試磁盤空間錯誤的規范,您可以嘗試:

before do
  allow_any_instance_of(File).to receive(:open) { raise Errno::ENOSPC }
  # or maybe # allow(File).to receive(:write) { raise Errno::ENOSPC }
  # or       # allow(FileUtils).to receive(:cp) { raise Errno::ENOSPC }
  # or some combination of these 3...
end

it 'handles an out of disk space error' do
  expect{ my_disk_cache.set('key1', 'key2', [...]) }.to # your logic for how BuildCache::DiskCache should handle the error here.
end

但是有兩個問題:

1) Errno::ENOSPC可能不是您實際看到的錯誤。 該錯誤符合您的問題中的描述,但根據您的lib及其運行的系統的特性,您可能不會收到Errno::ENOSPC錯誤。 也許你首先用盡RAM並且正在使用Errno::ENOMEM ,或者你可能有太多文件描述符打開並且正在獲得Errno::EMFILE 當然,如果你想要嚴格,你可以處理所有這些,但這是耗時的,你會得到減少回報處理更隱晦的錯誤。

有關 Errno錯誤的更多信息, 請參閱此處。

2)該解決方案涉及在特定類上存根特定方法。 File.open )這並不理想,因為它將測試的設置與代碼中的實現相結合。 也就是說,如果你重構BuildCache::DiskCache#set為不使用File.open ,那么即使方法可能正確,此測試也可能會失敗。

也就是說, File.open相當低級。 我知道有些FileUtils方法使用File.open (值得注意的是, FileUtils.cp ),所以我只想使用首先建議allow_any_instance_of線。 我希望能處理你的大部分用例。

或者,有一個名為fakefs的工具可以幫助您解決這個問題。 我不熟悉它,但它可能具有幫助測試此類錯誤的功能。 你可能想看看它。

您可以使用您需要測試的方法中發生的任何方法調用,並將它們存根以便引發錯誤。 例如, FileUtils.touch被多次調用,所以我們可以這樣做:

it 'handles file write error gracefully' do
  allow(FileUtils).to receive(:touch).and_raise('oh no')
  # your expectations
  # your test trigger
end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM