RSpec: 如何测试哈希数组中键的存在?
RSpec: How to test existence of keys in an array of hashes?
我有一个 class:
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
方法returns 哈希数组。数组的长度是50个元素。
每个散列都有完全相同的键。大约有20个键。
我不确定对该方法进行单元测试的最佳方式是什么。我如何检查该方法是否确实返回了一个数组,每个散列都具有这些键?一些散列值可能为零,所以我不认为我会测试这些值。
这将有助于:
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
假设 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
我对此采取了稍微不同的策略。错误报告不会告诉您太多信息,但它们会让您知道要查看:
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
json
和 ids
方法只是:
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
这只会对一行有帮助
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
简单!
我有一个 class:
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
方法returns 哈希数组。数组的长度是50个元素。
每个散列都有完全相同的键。大约有20个键。
我不确定对该方法进行单元测试的最佳方式是什么。我如何检查该方法是否确实返回了一个数组,每个散列都具有这些键?一些散列值可能为零,所以我不认为我会测试这些值。
这将有助于:
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
假设 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
我对此采取了稍微不同的策略。错误报告不会告诉您太多信息,但它们会让您知道要查看:
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
json
和 ids
方法只是:
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
这只会对一行有帮助
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
简单!