【问题标题】:RSpec: How to test existence of keys in an array of hashes?RSpec:如何测试哈希数组中键的存在?
【发布时间】:2015-04-29 17:01:38
【问题描述】:

我有一堂课:

class ApiParser
  def initialize
    ..
  end

  def api_data
    # returns an array of hashes like so:
    # [{ answer: "yes", name: "steve b" age: 22, hometown: "chicago", ... },
    # { answer:"unsure", name: "tom z", age: 44, hometown: "baltimore" , ... },
    # { answer: "no", name: "the brah", age: nil, hometown: "SF", ... }, 
    # { ... }, { ... }, ... ]
  end
end

该方法返回一个哈希数组。数组长度为 50 个元素。

每个散列都有完全相同的键。大约有 20 个键。

我不确定对这种方法进行单元测试的最佳方法是什么。如何检查该方法是否确实返回了一个数组,其中每个哈希都具有这些键?一些哈希值可能为零,所以我不认为我会测试这些值。

【问题讨论】:

    标签: ruby unit-testing hash rspec


    【解决方案1】:

    这将只帮助一行

    describe '#api_data' do
      subject { ApiParser.new.api_data }
      let(:expected_keys) { [:key1, :key2, :key3] }
    
      it { is_expected.to all(contain_exactly(expected_keys)) }
    end
    

    简单!

    【讨论】:

      【解决方案2】:

      我对此采取了稍微不同的策略。错误报告并没有告诉您太多信息,但它们让您知道要查看:

      describe 'User Management: `/api/users`', type: :request do
        let(:required_keys) { %i(id email created_at updated_at) }
        let(:optional_keys) {
          %i(first_name last_name gender birthday bio phone role                                                                                     
             profile_image_url notification_preferences custom_group_order                                                                            
             archived timezone)
        }
        let(:keys) { required_keys + optional_keys }
      
        shared_examples 'a user object' do
          it 'has values for required keys' do
            subject.slice(*required_keys).values.should all be
          end
      
          its(:keys) { should include(*keys) }
        end
      
        shared_examples 'a users collection' do
          it { should be_an(Array) }
      
          it 'has all defined keys' do
            subject.map(&:keys).should all include(*keys)
          end
      
          it 'has values for required keys' do
            subject.map_send(:slice, *required_keys).map(&:values).flatten.should all be
          end
        end
      end
      

      这些的危险在于它们不需要用户集合是非空的。如果返回一个空数组,则通过。

      我将这些测试包含在一个对大小进行适当检查的测试中:

      describe 'GET to /api/users/visible' do
        let(:user) { Fabricate(:user) }
      
        subject { json[:users] }
      
        shared_examples 'a correct response' do
          it_should_behave_like 'a users collection'
      
          specify { controller.should respond_with :success }
      
          it { should have(members.size).items }
      
          it 'returns matching user ids' do
            ids(subject).should =~ ids(members)
          end
        end
      
        context 'with no groups' do
          let(:members) { [] }
      
          before { get '/api/users/visible', nil, auth_headers(user) }
      
          it_should_behave_like 'a correct response'
        end
      end
      

      jsonids 方法只是:

      def json
        JSON.parse(response.body, symbolize_names: true) if response.try(:body).try(:present?)
      end
      
      def ids(*from)
        Array.wrap(*from).map do |item|
          if item.respond_to?(:id)
            item.send(:id)
          elsif item.is_a?(Hash)
            item[:id] || item['id']
          end
        end
      end
      

      【讨论】:

        【解决方案3】:

        假设arr 是哈希数组。让:

        a = arr.map { |h| h.keys.sort }.uniq
        

        那么当且仅当所有哈希值都具有相同的n 键:

        a.size == 1 && a.first.size == n
        

        这很容易测试。

        如果您在数组keys 中获得了所需的键,那么测试是:

        a.size == 1 && a.first == keys.sort
        

        【讨论】:

        • 嘿,卡里。此测试代码的描述性不是很强,这与 RSpec 试图完成的目标背道而驰。这不会表明哪个哈希/数组索引失败。对于不可排序的键,它会彻底失败,例如arr = [{1 => 'val1', '2' => 'val2'}].
        【解决方案4】:

        这会有所帮助:

        describe "your test description" do
          let(:hash_keys) { [:one, :two].sort } # and so on
        
          subject(:array) { some_method_to_fetch_your_array }
        
          specify do
            expect(array.count).to eq 50
        
            array.each do |hash|
              # if you want to ensure only required keys exist
              expect(hash.keys).to contain_exactly(*hash_keys)
              # OR if keys are sortable
              # expect(hash.keys.sort).to eq(hash_keys)
        
              # if you want to ensure that at least the required keys exist
              expect(hash).to include(*hash_keys)
            end
          end
        end
        

        这种方法的一个问题是:如果测试失败,您将无法准确找出导致失败的数组索引。添加自定义错误消息会有所帮助。 类似以下的内容

        array.each_with_index do |hash, i|
          expect(hash.keys).to contain_exactly(*hash_keys), "Failed at index #{i}"
        end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-08-22
          • 2012-08-10
          • 1970-01-01
          • 1970-01-01
          • 2016-11-27
          • 2014-07-12
          • 1970-01-01
          相关资源
          最近更新 更多