代码之家  ›  专栏  ›  技术社区  ›  John Topley

如何使用RSpec模拟/存根文件及其内容的目录?

  •  4
  • John Topley  · 技术社区  · 16 年前

    不久前我问 How to test obtaining a list of files within a directory using RSpec? “虽然我得到了一些有用的答案,但我仍然被困在这里,因此我提出了一个新问题,其中有一些关于我要做什么的细节。

    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
    
    3 回复  |  直到 9 年前
        1
  •  4
  •   nas    16 年前

    我假设你有一个方法,获取所有文件,然后计算散列。我们称之为方法 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
    

    正如我之前所回答的,我们将stub Find.Find和File.read。但是,我们不会存根compute\u hash方法,因为您需要检查文件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
    

    为了简单起见,我只是读取文件体并将其传递给 计算\u哈希 方法并生成哈希。但是,如果 方法也在文件上使用其他一些方法来生成哈希。然后,您可以将它们存根并返回一个值以传递给 计算\u哈希 计算\u哈希 方法,如果它是公共方法并且只在 获取\u文件\u哈希

    关于不显示隐藏文件;您可以使用一个库来删除私有文件,也可以使用自己的方法来实现这一点。在前一种情况下,您不需要编写任何测试(假设库经过了良好的测试),在后一种情况下,您需要为那个单独的方法而不是这个方法进行测试。

    用于测试当文件内容发生变化时重新计算其哈希值;我猜你一定有某种触发哈希重新计算的事件。只需调用该事件方法并断言文件哈希匹配。

        2
  •  1
  •   Sam Phillips    16 年前

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

        3
  •  1
  •   Robert Speicher    16 年前

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