On Dec 21, 2007, at 1:30 PM, jimmy zimmerman wrote:
> I'm building an http communicator class for a web service API
> wrapper and I'm trying to go through the BDD process in doing so.
> I'm having a bit of a struggle figuring out how to set up the tests
> in relation to isolating things appropriately as well as testing
> behavior vs testing implementation.
>
> Specifically, I'm trying to set up a post method on my
> HttpCommunicator so I have the following:
>
> describe FamilyTreeApi::HttpCommunicator, "post" do
> it "should accept an endpoint and an xml string to post" # I'm okay
> with this one
> it "should perform post content to given endpoint"
> it "should return a response object"
> end
>
> I have written/passed the tests for the first spec, but I'm having
> troubles figuring out how to verify behavior for the second and
> third, and how to mock/stub it up. I'll be using the 'net/https'
> standard libraries to implement the POST action, and I know that it
> requires the use of a URI instance, a Net::HTTP instance, and a
> Net::HTTP::Post request instance.
>
Yep - I was doing something like that just yesterday, excepting
fetching a feed with the URI and Net:HTTP classes.
The way I got around it was to write one method which encapsulated
the behaviour of the URI.parse (stubbing a class method which
returned a mock). The second method would wrap the first - so
something like this:
def get_parsed_url
URI.parse(url)
end
def get_feed
Net::HTTP.get_response(get_parsed_url)
end
This allows me to stub out get_parsed_url when I'm testing the
get_feed method, and ignore the URI class altogether.
Another way to get around this sort of thing is by passing mock
objects into constructors, a la "Dependency Injection". That would
go something like this:
class Foo
def initialize(http_class = Net::HTTP, uri_class = URI)
@http_class, @uri_class = http_class, uri_class
end
def get_parsed_url
@uri_class.parse(url)
end
def get_feed
@http_class.get_response(get_parsed_url)
end
end
This allows you to pass in mock objects (mock classes) for your
tests, but it still allows the production code to default to what you
really want (the Net::HTTP and URI classes). It's also going to make
your code more flexible, in the case that you ever wanted to swap out
Net::HTTP or URI for an alternative implementation.
Hope that helps,
Scott
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users