Правильный способ издеваться над классами ядра ruby

#ruby #rspec #rspec-mocks

#ruby #rspec #rspec-издевается

Вопрос:

Я хочу знать, одобрено ли это решение сообществом mocking object в ruby. Если нет, пожалуйста, опишите, почему и как я могу улучшить дизайн кода или, возможно, протестировать.

Рассмотрим, что у меня есть следующий код.

lib/config_loader.rb

 class ConfigLoader
  HOME_DIR = '~/my/home_dir'.freeze
  ...

  def load(path)
    path = File.expand_path(path)

    if File.exist?(path)
      File.read(path) 
    else
      File.read(HOME_DIR)
    end
  end
end
  

При тестировании я на самом деле не хочу, чтобы что-либо создавалось в соответствии path с тем, что я определил в переменной, поэтому я просто хочу издеваться над этим поведением

spec/lib/config_loader_spec.rb

 RSpec.describe ConfigLoader do
  describe '.load' do
    subject { described.class.new.load(path) }

    let(:path) { 'path/that/should/exist' }

    context 'when path' do
      before do 
        allow(File).to receive(:exist?).with(path).and_return(true)
        allow(File).to receive(:read).with(path).and_return('my content')
      end

      it { expect { subject }.to_not raise_error { Errno::ENOENT }
    end
  end
end
  

может быть, мне следует сделать что-то class_double из File Class. Я не уверен в том, как я предоставил, поэтому мне нужна некоторая информация о том, как это сделать обычным / передовым способом

Комментарии:

1. Проверьте FakeFS

Ответ №1:

Один из фундаментальных принципов разработки / дизайна, основанного на тестировании / поведении, заключается в том, чтобы не издеваться над тем, чем вы не владеете (придуман в книге Growing Object-Oriented Software, руководствуясь тестами Стива Фримена и Нэта Прайса).

Ваш пример нарушает этот принцип: вы не являетесь владельцем File , поэтому вы не должны издеваться над ним.

Вместо этого вы могли бы создать свою собственную абстракцию для взаимодействия с файловой системой, которая обладает только той функциональностью, которая вам действительно требуется. Затем вы можете создать две реализации этой абстракции: ту, которая использует File класс Ruby, и макет, который ничего не делает. Если вы хотите пофантазировать, вы даже можете создать тот, который имитирует файловую систему в памяти.

Конечно, теперь вы просто решили проблему: теперь у вас есть непроверенный код в вашей реализации файловой абстракции. Однако в идеале этот код должен быть «почти» тривиальным. И, очевидно, вы все равно можете провести интеграционный тест как для вашей реализации файловой абстракции, так и для интеграционного теста, в ConfigLoader котором используется реальная реализация вместо макета или симуляции.

Вот некоторые дополнительные сведения, если вам интересно: