【问题标题】:How to mock/stub a directory of files and their contents using RSpec?如何使用 RSpec 模拟/存根文件目录及其内容?
【发布时间】:2010-06-04 14:47:07
【问题描述】:

不久前我问过“How to test obtaining a list of files within a directory using RSpec?”,虽然我得到了一些有用的答案,但我仍然卡住了,因此提出了一个新问题,其中包含有关我正在尝试做什么的更多细节。

我正在编写我的第一个 RubyGem。它有一个模块,其中包含一个类方法,该方法返回一个数组,该数组包含指定目录中的非隐藏文件列表。像这样:

files = Foo.bar :directory => './public'

该数组还包含一个表示有关文件的元数据的元素。这实际上是从文件内容生成的哈希哈希,其想法是即使更改单个文件也会更改哈希。

我已经编写了待处理的 RSpec 示例,但我真的不知道如何实现它们:

it "should compute a hash of the files within the specified directory"
it "shouldn't include hidden files or directories within the specified directory"
it "should compute a different hash if the content of a file changes"

我真的不想让测试依赖于充当夹具的真实文件。如何模拟或存根文件及其内容? gem 实现将使用Find.find,但正如我对另一个问题的答案之一所说,我不需要测试库。

我真的不知道如何编写这些规范,所以非常感谢任何帮助!


编辑:下面的cache 方法是我要测试的方法:

require 'digest/md5'
require 'find'

module Manifesto   
  def self.cache(options = {})
    directory = options.fetch(:directory, './public')
    compute_hash  = options.fetch(:compute_hash, true)
    manifest = []
    hashes = ''
    Find.find(directory) do |path|

      # Only include real files (i.e. not directories, symlinks etc.)
      # and non-hidden files in the manifest.
      if File.file?(path) && File.basename(path)[0,1] != '.'
        manifest << "#{normalize_path(directory, path)}\n"
        hashes += compute_file_contents_hash(path) if compute_hash
      end
    end

    # Hash the hashes of each file and output as a comment.
    manifest << "# Hash: #{Digest::MD5.hexdigest(hashes)}\n" if compute_hash
    manifest << "CACHE MANIFEST\n"
    manifest.reverse
  end

  # Reads the file contents to calculate the MD5 hash, so that if a file is
  # changed, the manifest is changed too.
  def self.compute_file_contents_hash(path)
    hash = ''
    digest = Digest::MD5.new
    File.open(path, 'r') do |file|
      digest.update(file.read(8192)) until file.eof
      hash += digest.hexdigest
    end
    hash
  end

  # Strips the directory from the start of path, so that each path is relative
  # to directory. Add a leading forward slash if not present.
  def self.normalize_path(directory, path)
    normalized_path = path[directory.length,path.length]
    normalized_path = '/' + normalized_path unless normalized_path[0,1] == '/'
    normalized_path
  end      
end

【问题讨论】:

    标签: ruby rspec bdd


    【解决方案1】:

    我将假设您有一些方法可以获取所有文件,然后计算哈希值。让我们调用该方法get_file_hash 并将其定义如下。

    def get_file_hash
      file_hash = {}
      Find.find(Dir.pwd) do |file| 
        file_hash[file] = compute_hash(File.read(file))
      end
      file_hash
    end
    

    正如我之前回答的那样,我们将存根 Find.find 和 File.read。但是,我们不会存根 compute_hash 方法,因为您要检查文件哈希。我们将让compute_hash 方法创建文件内容的实际哈希。

    describe "#get_file_hashes"
    
      ......
    
      before(:each)
        File.stubs(:find).returns(['file1', 'file2'])
        File.stubs(:read).with('file1').returns('some content')
        File.stubs(:read).with('file2').returns('other content')
      end
    
      it "should return the hash for all files"
    @whatever_object.get_file_hashes.should eql({'file1' => "hash you are expecting for 'some content'", 'file2' => "hash you are expecting for 'other content'"})
    end
    
    end
    

    为简单起见,我只是读取文件正文并将其传递给compute_hash 方法并生成哈希。但是,如果您的 compute_hash 方法还使用文件中的其他一些方法来生成哈希。然后,您可以对它们进行存根并返回一个要传递给compute_hash 方法的值。虽然,如果 compute_hash 方法是一个公共方法,我会更愿意单独测试它,并且只是在 get_file_hash 方法中存根它的调用。

    关于不显示隐藏文件;您将为此使用一个库来省略私有文件,或者将拥有自己的方法来做到这一点。在前一种情况下,您不需要编写任何测试(假设库已经过良好测试),而在后一种情况下,您需要测试那个单独的方法而不是这个。

    用于在文件内容更改时重新计算文件的哈希值;我想你一定有某种事件触发了哈希的重新计算。只需调用该事件方法并断言文件哈希匹配即可。

    【讨论】:

    • 谢谢。我刚刚编辑了问题以包含我要测试的实际代码。
    • 我将分叉宣言,并在完成更改后向您发送拉取请求。听起来不错?
    • 太棒了,听起来很完美。谢谢!
    【解决方案2】:

    MockFS 能帮到你吗? http://mockfs.rubyforge.org/

    我看到在回答您的原始问题时提到了 Fake FS,但我不确定您是否可以使用它来模拟文件内容。

    【讨论】:

      【解决方案3】:

      你能模拟你用来读取文件的任何方法返回的值吗?这样您就可以测试预期的哈希值,并至少确保正在读取文件。

      编辑:看起来 FakeFS 确实有一个 File.read 方法,所以也许这会起作用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-31
        • 2011-07-14
        • 2021-08-07
        • 2014-02-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多