cool episode! @joelq for QuoteService
, what was behind the decision to have a class method .fetch
that instantiates the object rather than just call QuoteService.new(item).fetch
directly? I have lots of adapter/service objects in the app Iām working on and weāve chosen to use instance methods instead of class methods for no reason other than it looks a bit more OO to us. Iām curious to hear your reasoning behind your approach here.
@evan-007, I think Joelās example was just meant to be simple to read for the purposes of learning the technique.
I often find that I end up creating a class method for ease-of-setup, but that I end up having that class method simply create an instance and call an instance method with the same name:
class QuoteService
def self.fetch(item)
new(item).fetch
end
def initialize(item)
@item = item
end
def fetch
# do stuff
end
end
This approach works well if you end up having temporary state in your objects that you want to handle using OO principles.
@geoffharcourt is correct. @evan-007 I agree with you that actually doing work at the instance level is preferable from an OO point of view. While all the logic is all happening in an instance, Iāll often add a class method of the same name that just instantiates the object and calls the method on it. You can think of it as an alias of sorts. Iām particularly prone to use this pattern on service objects due to the way they are used.
Thereās an article on our blog that digs deeper into this idea: Meditations on a Class Method
thanks @geoffharcourt and @joelq! that makes sense. I suppose an added benefit of using a class method is that itās a bit more concise in the tests to stub out a class method vs something like
service = double 'quote_service', fetch: valid_resp
allow(QuoteService).to receive(:new).with(some_args).and_return service
This video was really great, I enjoyed every minute.
Thanks guys for this interesting episode! I wonder though what approach would you take when testing interaction with a SOAP API that requires sending many requests per use case. Do you guys have any experience with that?
@sauloperez when sending multiple requests per interaction, you can still use all of the techniques described in the episode:
Stubbing the ābackendā
When unit-testing, you can create multiple stubs on the ābackendā, one for each call that you would make to it.
Stubbing the network
- If you use VCR, it should be able to capture multiple requests and then replay them
- If you use WebMock, you can create multiple mocks, one for each web request
Swapping out the ābackendā for a fake
If youāve created a fake backend object, you should be fine as long as it implements the same interface as the real backend object. You can make as many calls to it as you need.
Swapping out the real service for a fake
If you are making real HTTP requests to a fake server, there are no limits on how many requests you can make within a single test. As long as the proper endpoints are defined, you should be fine.
This is a common situation when dealing with API authentication, such as OAuth, where you need to make multiple requests as part of a single interaction.