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: https://robots.thoughtbot.com/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.