RSpec:如何测试哈希数组中键的存在性?

4

我有一个类:

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个键。

我不确定测试此方法的最佳方式是什么。如何检查该方法确实返回具有这些键的每个哈希的数组?一些哈希值可能为nil,因此我不认为我会测试值。

4个回答

15

这将有所帮助:

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

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

简单!

0

我采取了稍微不同的方法。错误报告并没有告诉你太多,但它们让你知道需要查看:

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

0
假设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

嗨,Cary。这个测试代码不太具有描述性,这与 RSpec 的目标相违背。而且它不会指示哪个哈希/数组索引失败了。对于无法排序的键(例如 arr = [{1 => 'val1', '2' => 'val2'}]),它将直接失败。 - SHS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接