Dry :: Web :: Container, выдающий различные объекты с несколькими вызовами для разрешения - PullRequest
1 голос
/ 13 марта 2019

Я пытаюсь написать тест, чтобы утверждать, что все определенные операции вызываются при успешном запуске.У меня есть операции для данного процесса, определенные в списке, и я разрешаю их из контейнера следующим образом:

class ProcessController
  def call(input)
    operations.each { |o| container[o].(input) }
  end

  def operations
    ['operation1', 'operation2']
  end

  def container
    My::Container # This is a Dry::Web::Container
  end
end

Затем я проверяю следующее:

RSpec.describe ProcessController do
  let(:container) { My::Container } 

  it 'executes all operations' do
    subject.operations.each do |op|
      expect(container[op]).to receive(:call).and_call_original
    end

    expect(subject.(input)).to be_success
  end
end

Это не удается, потому чтовызов container[operation_name] изнутри ProcessController и изнутри теста дает разные экземпляры операций.Я могу это проверить, сравнив идентификаторы объектов.Кроме этого, я знаю, что код работает правильно и все операции вызываются.

Контейнер сконфигурирован для автоматической регистрации этих операций и был завершен до начала выполнения теста.

Как сделать так, чтобы при разрешении одного и того же ключа возвращался один и тот же элемент?

1 Ответ

0 голосов
/ 17 мая 2019

TL; DR - https://dry -rb.org / gems / dry-system / test-mode /


Привет, чтобы получитьзапрашиваемое поведение, вам нужно будет использовать опцию memoize при регистрации элементов в вашем контейнере.

Обратите внимание, что Dry::Web::Container наследует Dry::System::Container, который включает Dry::Container::Mixin, так что покаВ следующем примере используется dry-container, он по-прежнему применим:

require 'bundler/inline'

gemfile(true) do
  source 'https://rubygems.org'

  gem 'dry-container'
end

class MyItem; end

class MyContainer
  extend Dry::Container::Mixin

  register(:item) { MyItem.new }
  register(:memoized_item, memoize: true) { MyItem.new }
end

MyContainer[:item].object_id
# => 47171345299860
MyContainer[:item].object_id
# => 47171345290240

MyContainer[:memoized_item].object_id
# => 47171345277260
MyContainer[:memoized_item].object_id
# => 47171345277260

Однако, чтобы сделать это из Dry-Web, вам нужно либо запомнить все объекты, автоматически зарегистрированные под тем жепуть или добавьте магический комментарий # auto_register: false в начало файлов, которые определяют зависимости, и загрузите их вручную .

Заметки могут вызвать проблемы параллелизма в зависимости от того, какой сервер приложенийвы используете, и будут ли ваши объекты видоизменяться в течение жизненного цикла запроса, поэтому конструкция сухого контейнера не запоминает по умолчанию.

Другой, возможно, лучший вариант, это использовать заглушки :

# Extending above code
require 'dry/container/stub'
MyContainer.enable_stubs!
MyContainer.stub(:item, 'Some string')

MyContainer[:item]
# => "Some string"

Примечание:

dry-system обеспечивает входjector так что вам не нужно вызывать контейнер вручную в ваших объектах, чтобы ваш контроллер процесса стал чем-то вроде:

class ProcessController
  include My::Importer['operation1', 'operation2']

  def call(input)
    [operation1, operation2].each do |operation|
      operation.(input)
    end
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...