Тестирование Ruby-модулей с помощью rspec

У меня плохое время найти в SO/Google этот конкретный случай. У меня есть модуль с функциями и для их использования вы должны создать класс, который включает/расширяет модуль в зависимости от того, нужны ли методы экземпляра или методы класса.

module A
  def say_hello name
    "hello #{name}"
  end

  def say_bye
    "bye"
  end
end

Как проверить этот модуль с помощью rspec?

У меня есть что-то вроде этого, и я не уверен, где именно я должен создать класс и расширить модуль.

describe A do
  class MyClass
    extend A
  end

  before(:each) { @name = "Radu" }

  describe "#say_hello" do
    it "should greet a name" do
      expect(Myclass.say_hello(@name)).to eq "hello Radu"
    end
  end
end

Спасибо!

Ответ 1

Вы можете создать анонимный класс в своих тестах:

describe A do
  let(:extended_class) { Class.new { extend A } }
  let(:including_class) { Class.new { include A } }

  it "works" do
    # do stuff with extended_class.say_hello
    # do stuff with including_class.new.say_hello
  end
end

Чтобы увидеть что-то подобное в реальном коде, я использовал эту стратегию для тестирования моего attr_extras lib.

Тем не менее, include и extend являются стандартными функциями Ruby, поэтому я не буду тестировать, что каждый модуль работает как при включении, так и при расширении - обычно это заданный.

Если вы создаете именованный класс в тесте, как и в своем вопросе, я считаю, что класс будет существовать глобально на протяжении всего вашего тестового прогона. Таким образом, этот класс будет протекать между каждым тестом вашего тестового набора, потенциально вызывающим конфликты где-то.

Если вы используете let для создания анонимного класса, он будет доступен только в этом конкретном тесте. Не существует глобальной постоянной, указывающей на нее, которая может конфликтовать с другими тестами.

Ответ 2

Чтобы помочь будущим читателям, вот пример, который я получил, используя решение @henrik-n:

# slim_helpers.rb
module SlimHelpers

  # resourceToTitle converts strings like 'AWS::AutoScaling::AutoScalingGroup'
  # to 'Auto Scaling Group'
  def resourceToTitle(input)
    input.split('::')[-1].gsub(/([A-Z])/, ' \1').lstrip
  end

end

# slim_helpers_spec.rb
require_relative '../slim_helpers'

describe SlimHelpers do

  # extended class
  let(:ec) { Class.new { extend SlimHelpers } }

  it "converts AWS resource strings to titles" do
    out = ec.resourceToTitle('AWS::AutoScaling::AutoScalingGroup')
    expect(out).to eq 'Auto Scaling Group'
  end
end