在 Ruby - Rails 项目中存根 .sample 使用 Il8n gem
Stubbing .sample in Ruby - Rails project using Il8n gem
我正在开发描述生成器功能,该功能将查看对象属性并通过从已设置的各种语言环境(多种语言)中提取字符串来填充描述。
我有以下代码
module Rooms
class DescriptionGenerator
attr_reader :room, :locale
def initialize(room, locale="en")
@room = room
@locale = locale
end
private
def t(key, options={})
I18n.t("rooms.description_generator.#{key}", options.merge({ locale: locale }))
end
def wifi
t("wifi", room_type: room.room_type.type).values.sample if room.wifi
end
然后我有以下测试:
describe "#wifi" do
let!(:room_with_wifi) { create(:room, :visible, wifi: true) }
let!(:room) { create(:room) }
#This one is failing
it "returns wifi sentence if room has wifi" do
sentence = I18n.t('rooms.description_generator.wifi', room_type: room_with_wifi.room_type.type).values.sample
expect(Rooms::DescriptionGenerator.new(room_with_wifi,"en").send(:wifi)).to eq (sentence)
end
it "returns nil if room does not have wifi" do
expect(Rooms::DescriptionGenerator.new(room,"en").send(:wifi)).to eq nil
end
end
我的问题是"What is the best way to test this given the use of sample?"
我最初的解决方案(我很确定不推荐)是添加:
class DescriptionGenerator
def sample(arr)
if Rails.env.test?
arr.values.first
else
arr.sample.values
end
end
end
'enforced' RSpec 将从我的语言环境中选择第一个选项,如下所示:
three_positive_reviews:
a: "This is not so great"
b: "This %{string_for_interpolation} is great."
c: "This is bad"
这一切都过去了,直到我将要插入的字符串添加到测试中使用的第一个 (a) 中,并意识到在 i18n gem 中不支持数组内的插入(Interpolation in I18n array).
所以我重构为:
def t(key, options={})
value = I18n.t("rooms.description_generator.#{key}")
key = "#{key}.#{sample(value.keys)}" if value.is_a?(Hash)
I18n.t("rooms.description_generator.#{key}", options.merge({ locale: locale }))
end
def sample(keys)
if Rails.env.test?
keys.first
else
keys.sample
end
end
这现在通过了我的测试套件 - 但是在详细研究了这个之后想寻求更优化的解决方案以及我如何更适当地测试(可能通过存根样本??)而不使用行
if Rails.env.test?
我会执行以下操作(我没有 运行 代码,认为):
let(:room) { create(:room) }
let(:locale) { 'en' }
let(:generator) { Rooms::DescriptionGenerator.new(room, locale) }
describe '#wifi' do
let(:wifi_sentences) do
I18n.t('rooms.description_generator.wifi', locale: locale)).values
end
context 'when the room has wifi' do
it 'returns wifi sentence' do
expect(generator.send(:wifi)).to be_in(wifi_sentences)
end
end
context 'when the room has no wifi' do
before do
allow(room).to receive(:wifi).and_return(false) # or nil, don't know
end
it 'returns nil' do
expect(generator.send(:wifi)).to be(nil)
end
end
end
希望这对您有所帮助:)
感谢 Victor 的回答 - 对重构我的测试非常有帮助。我想 post 提出我的最终解决方案,该解决方案考虑了您的建议并进行了一些调整,以防对其他人有用。
let(:room) { create(:room) }
let(:locale) { 'en' }
let(:generator) { Rooms::DescriptionGenerator.new(room, locale) }
describe "#laundry" do
it "returns wifi sentence if room has wifi" do
sentence = "This apartment is equipped with laundry facilities."
room.laundry = true
expect(generator.send(:laundry)).to eq(sentence)
end
it "returns nil if room is not have laundry" do
expect(generator.send(:laundry)).to eq nil
end
end
这适用于一个简单的单一选项语言环境:
laundry: "This %{room_type} is equipped with laundry facilities."
然而,由于 Rails i18n 无法在数组中插入字符串(即当提供多个键值对时),我存根了示例。
context "translations with multiple options that require interpolation" do
before do
allow(generator).to receive(:sample) { |keys| keys.first }
end
describe "#three_positive_reviews" do
context 'when the room has 3 positive reviews' do
before do
3.times do
create(:feedback, :non_external, :positive, room: room)
end
end
it "returns three_positive_reviews sentence" do
sentence = "This apartment is highly reviewed"
expect(generator.send(:three_positive_reviews)).to eq(sentence)
end
end
context 'when the room does not have 3 positive reviews' do
it "returns nil" do
expect(generator.send(:three_positive_reviews)).to eq nil
end
end
然后能够将我的代码中的示例方法重构为:
def sample(keys)
keys.sample
end
这对我来说似乎比我在问题中 post 的原始解决方案更简洁。
我正在开发描述生成器功能,该功能将查看对象属性并通过从已设置的各种语言环境(多种语言)中提取字符串来填充描述。
我有以下代码
module Rooms
class DescriptionGenerator
attr_reader :room, :locale
def initialize(room, locale="en")
@room = room
@locale = locale
end
private
def t(key, options={})
I18n.t("rooms.description_generator.#{key}", options.merge({ locale: locale }))
end
def wifi
t("wifi", room_type: room.room_type.type).values.sample if room.wifi
end
然后我有以下测试:
describe "#wifi" do
let!(:room_with_wifi) { create(:room, :visible, wifi: true) }
let!(:room) { create(:room) }
#This one is failing
it "returns wifi sentence if room has wifi" do
sentence = I18n.t('rooms.description_generator.wifi', room_type: room_with_wifi.room_type.type).values.sample
expect(Rooms::DescriptionGenerator.new(room_with_wifi,"en").send(:wifi)).to eq (sentence)
end
it "returns nil if room does not have wifi" do
expect(Rooms::DescriptionGenerator.new(room,"en").send(:wifi)).to eq nil
end
end
我的问题是"What is the best way to test this given the use of sample?"
我最初的解决方案(我很确定不推荐)是添加:
class DescriptionGenerator
def sample(arr)
if Rails.env.test?
arr.values.first
else
arr.sample.values
end
end
end
'enforced' RSpec 将从我的语言环境中选择第一个选项,如下所示:
three_positive_reviews:
a: "This is not so great"
b: "This %{string_for_interpolation} is great."
c: "This is bad"
这一切都过去了,直到我将要插入的字符串添加到测试中使用的第一个 (a) 中,并意识到在 i18n gem 中不支持数组内的插入(Interpolation in I18n array).
所以我重构为:
def t(key, options={})
value = I18n.t("rooms.description_generator.#{key}")
key = "#{key}.#{sample(value.keys)}" if value.is_a?(Hash)
I18n.t("rooms.description_generator.#{key}", options.merge({ locale: locale }))
end
def sample(keys)
if Rails.env.test?
keys.first
else
keys.sample
end
end
这现在通过了我的测试套件 - 但是在详细研究了这个之后想寻求更优化的解决方案以及我如何更适当地测试(可能通过存根样本??)而不使用行
if Rails.env.test?
我会执行以下操作(我没有 运行 代码,认为):
let(:room) { create(:room) }
let(:locale) { 'en' }
let(:generator) { Rooms::DescriptionGenerator.new(room, locale) }
describe '#wifi' do
let(:wifi_sentences) do
I18n.t('rooms.description_generator.wifi', locale: locale)).values
end
context 'when the room has wifi' do
it 'returns wifi sentence' do
expect(generator.send(:wifi)).to be_in(wifi_sentences)
end
end
context 'when the room has no wifi' do
before do
allow(room).to receive(:wifi).and_return(false) # or nil, don't know
end
it 'returns nil' do
expect(generator.send(:wifi)).to be(nil)
end
end
end
希望这对您有所帮助:)
感谢 Victor 的回答 - 对重构我的测试非常有帮助。我想 post 提出我的最终解决方案,该解决方案考虑了您的建议并进行了一些调整,以防对其他人有用。
let(:room) { create(:room) }
let(:locale) { 'en' }
let(:generator) { Rooms::DescriptionGenerator.new(room, locale) }
describe "#laundry" do
it "returns wifi sentence if room has wifi" do
sentence = "This apartment is equipped with laundry facilities."
room.laundry = true
expect(generator.send(:laundry)).to eq(sentence)
end
it "returns nil if room is not have laundry" do
expect(generator.send(:laundry)).to eq nil
end
end
这适用于一个简单的单一选项语言环境:
laundry: "This %{room_type} is equipped with laundry facilities."
然而,由于 Rails i18n 无法在数组中插入字符串(即当提供多个键值对时),我存根了示例。
context "translations with multiple options that require interpolation" do
before do
allow(generator).to receive(:sample) { |keys| keys.first }
end
describe "#three_positive_reviews" do
context 'when the room has 3 positive reviews' do
before do
3.times do
create(:feedback, :non_external, :positive, room: room)
end
end
it "returns three_positive_reviews sentence" do
sentence = "This apartment is highly reviewed"
expect(generator.send(:three_positive_reviews)).to eq(sentence)
end
end
context 'when the room does not have 3 positive reviews' do
it "returns nil" do
expect(generator.send(:three_positive_reviews)).to eq nil
end
end
然后能够将我的代码中的示例方法重构为:
def sample(keys)
keys.sample
end
这对我来说似乎比我在问题中 post 的原始解决方案更简洁。