I'm trying write a test to assert that all defined operations are called on a successful run. I have the operations for a given process defined in a list and resolve them from a container, like so:
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
Then I test is as follows:
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
This fails because calling container[operation_name] from inside ProcessController and from inside the test yield different instances of the operations. I can verify it by comparing the object ids. Other than that, I know the code is working correctly and all operations are being called.
The container is configured to auto register these operations and has been finalized before the test begins to run.
How do I make resolving the same key return the same item?
 
                        
TL;DR - https://dry-rb.org/gems/dry-system/test-mode/
Hi, to get the behaviour you're asking for, you'd need to use the
memoizeoption when registering items with your container.Note that
Dry::Web::ContainerinheritsDry::System::Container, which includesDry::Container::Mixin, so while the following example is usingdry-container, it's still applicable:However, to do this from dry-web, you'd need to either memoize all objects auto-registered under the same path, or add the
# auto_register: falsemagic comment to the top of the files that define the dependencies and boot them manually.Memoizing could cause concurrency issues depending on which app server you're using and whether or not your objects are mutated during the request lifecycle, hence the design of dry-container to not memoize by default.
Another, arguably better option, is to use stubs:
Side note:
dry-systemprovides an injector so that you don't need to call the container manually in your objects, so your process controller would become something like: