【问题标题】:Stubbing .sample in Ruby - Rails project using Il8n gem在 Ruby 中存根 .sample - 使用 Il8n gem 的 Rails 项目
【发布时间】:2015-11-26 07:04:37
【问题描述】:

我正在开发一个描述生成器功能,该功能将查看对象属性并通过从已设置的各种语言环境(多种语言)中提取字符串来填充描述。

我有以下代码

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

我的问题是“在使用样本的情况下,最好的测试方法是什么?”

我最初的解决方案(我很确定不推荐)是添加:

class DescriptionGenerator
  def sample(arr)
    if Rails.env.test?
      arr.values.first
    else
      arr.sample.values
    end
  end
end

这“强制”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?

【问题讨论】:

    标签: ruby-on-rails ruby rspec internationalization


    【解决方案1】:

    我会做以下事情(我没有运行代码,我想):

    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
    

    希望这会有所帮助:)

    【讨论】:

      【解决方案2】:

      感谢 Victor 的回答 - 对重构我的测试非常有帮助。我想发布我的最终解决方案,它会考虑您的建议并进行一些调整,以防它对其他人有用。

      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
      

      这对我来说似乎比我在问题中发布的原始解决方案更干净。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多