Reputation: 2304
I want our app to speak to our microservice for sending emails via an API.
In tests (in RSpec), I want to say:
For example:
Upvotes: 2
Views: 2680
Reputation: 101811
Sending real HTTP requests from your app can have some serious drawbacks:
You also need to weigh having clear boundaries of each application vs test acuity. Properly respecting the app boundaries means that you only test that your app communicates with the collaborator(s) as specified by the API(s) and stub out the actual communication.
The con is of course that stubbing always has a cost when it comes to test acuity. You may miss bugs where the API does not work as documented or where you're simply testing for the wrong thing.
Webmock for example lets you stub out the HTTP layer completely. You can set expectations on the external calls and mock the return values.
stub_request(:post, "api.example.com").to_return(status: 201)
expect(a_request(:post, "www.example.com").
with(:body => {"a" => ["b", "c"]},
:headers => {'Content-Type' => 'application/json'})).to have_been_made
VCR on the other hand is kind of a middle road, it lets you perform real HTTP requests which it records to YML files and then plays back the results. Subsequent runs are faster and deterministic. VCR is a lot less arduous than setting up mock responses, however you still need to deal with setting up the initial state and cleaning up any side effects on the external service from your tests.
VCR.use_cassette("synopsis") do
response = Net::HTTP.get_response(URI('http://example.com'))
expect(response.body).to match("Example domain")
end
This is an example plucked from a real world app that uses the Flickr API:
RSpec.feature 'Importing photosets from flickr' do
include JavascriptTestHelpers
let(:user) { create(:admin, flickr_uid: 'xxx') }
before { login_as user }
let(:visit_new_photosets_path) do
VCR.use_cassette('photosets_import') { visit new_photoset_path }
end
scenario 'When I create a photoset it should have the correct attributes', js: true do
visit_new_photosets_path
VCR.use_cassette('create_a_photoset') do
click_button('Create Photoset', match: :first)
wait_for_ajax
end
find('.photoset', match: :first).click
expect(page).to have_content "Showcase"
expect(page).to have_content "Like a greatest hits collection, but with snow."
expect(page).to have_selector '.photo img', count: 10
end
end
Upvotes: 6
Reputation: 6834
You need to use message expectations, for example:
it "asks the project to trigger all hooks" do
expect(project).to receive(:execute_hooks).twice
expect(project).to receive(:execute_services).twice
expect(project).to receive(:update_merge_requests)
PostReceive.new.perform(...)
end
Regarding mailers check this other answer
Upvotes: 3