Ruby on Rails项目中请求体变化时如何Stub Mailjet API请求?
Hey there! I’ve dealt with this exact frustration before—when you generate a stub with WebMock but can’t reuse it because parts of the request body (like that reset password token) change every time. Let’s break down how to make your stubs flexible enough to handle dynamic content while still verifying the important parts.
Option 1: Use WebMock’s Hash Matchers for Flexible Body Matching
Instead of hardcoding the entire JSON string, let WebMock parse the request body into a hash and match against the fixed, critical fields. This ignores any dynamic values you don’t care about.
Here’s how to adjust your stub:
stub_request(:post, "https://api.mailjet.com/v3/send") .with( body: hash_including( "FromEmail" => "abc@abc.com", "FromName" => "abc", "To" => "abc@abc.com", "Subject" => "Forgot Password" ) )
If you want to add a little more rigor (like ensuring the dynamic part follows a pattern), you can use a regex for specific fields:
stub_request(:post, "https://api.mailjet.com/v3/send") .with( body: hash_including( "FromEmail" => "abc@abc.com", "FromName" => "abc", "To" => "abc@abc.com", "Subject" => "Forgot Password", "Text-part" => /^xV3SEtaoa1oyYYfY/ # Matches the fixed prefix of your token ) )
Option 2: Stub the Mailjet Client Directly (Instead of HTTP Requests)
If you’re using the official mailjet-ruby gem, it’s often cleaner to stub the client method rather than the raw HTTP call. This lets you work at a higher level and avoid dealing with request body formatting entirely.
Example:
# In your spec allow(Mailjet::Message).to receive(:send) do |message_params| # Assert that the parameters are correct expect(message_params[:FromEmail]).to eq("abc@abc.com") expect(message_params[:Subject]).to eq("Forgot Password") # Return a mock successful response { "Messages" => [{ "Status" => "success" }] } end
Bonus: Verify the Request Was Actually Made
To ensure your code is hitting the stub (and not the real API), you can add an assertion with WebMock’s have_requested:
expect(a_request(:post, "https://api.mailjet.com/v3/send") .with(body: hash_including("Subject" => "Forgot Password"))).to have_been_made.once
These approaches keep your stubs maintainable, even when dynamic parts of the request body change. No more copying and pasting updated JSON strings every time!
内容的提问来源于stack exchange,提问作者awsm sid

