I have this pattern come up over and over again:
class MyAdapter
include Container[:my_client]
def initialize(credentials, **deps)
@credentials = credentials
super(**deps)
end
end
class DoSomething
include Container[:my_adapter]
def call(account)
adapter = my_adapter.new(account.credentials)
# ...
end
end
module Container
register(:my_client) { MyClient }
register(:my_adapter) { MyAdapter }
end
RSpec.describe DoSomething
let(:response) { { some: :json } }
let(:client) { instance_double(MyClient, request: response) }
let(:client_class) { class_double(MyClient, new: client) }
let(:adapter_class) { class_double(MyAdapter, new: MyAdaper.new(my_client: client_class)) }
# -- or --
before { Container.stub(:my_client, client_class) }
subject(:something) { DoSomething.new(my_adapter: adapter).call(account) }
specify {
expect(adapter_class).to have_received(:new).with(credentials)
}
specify {
expect(client).to have_received(:request).with(some_data)
}
end
I have classes that need to be initialized with some data besides their dependencies (in this case, some API credentials), and I have to set up those tedious class+instance mocks.
I noticed dry-rails’ autoloader uses dry-system to somehow auto-“new” things things it discovers to register (eg, loading “app/whatever/my_command.rb” causes AppContainer["my_command"]
to return an instance of MyCommand
rather than the class itself. Is there a way to leverage that, but have control over the arguments that get passed to initialize
?
Or is the expected pattern to just never have any objects that have to be initialized with non-dependencies? (Note this is difficult for things like adapters, which tend to have several methods that take independent args like the params to the API call as well as some data that’s always the same, like credentials).
I’ve also tried thing like defining #new
as an instance method, so I can call it as many times as I want on an object, which is useful for tests, but feels gross otherwise.
def new(credentials, **deps)
self.class.new(credentials, **deps)
end