如何为基于Mailgun API的邮件发送服务编写RSpec测试
问题描述
我参照Mailgun的API文档编写了发送邮件的方法,代码如下:
def send_simple_message RestClient.post "https://api:YOUR_API_KEY"\ "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages", :from => "Excited User <mailgun@YOUR_DOMAIN_NAME>", :to => "bar@example.com, YOU@YOUR_DOMAIN_NAME", :subject => "Hello", :text => "Testing some Mailgun awesomness!" end
我把这个方法放到了ApplicationService的子类SendMailService中,控制器里通过以下代码调用:
SendMailService.new(param['email']).call
请问该如何编写对应的RSpec测试用例?
编写RSpec测试用例的步骤
1. 依赖准备
首先确保测试环境能拦截HTTP请求,避免真实调用Mailgun API。在Gemfile的测试组添加webmock:
# Gemfile group :test do gem 'webmock' end
执行bundle install后,在rails_helper.rb或spec_helper.rb中启用WebMock:
require 'webmock/rspec' WebMock.disable_net_connect!(allow_localhost: true)
2. 测试SendMailService
我们需要验证Service是否正确构造请求、发送到正确的API地址,以及参数是否符合预期。
创建spec/services/send_mail_service_spec.rb:
require 'rails_helper' RSpec.describe SendMailService do let(:recipient_email) { 'test@example.com' } let(:test_api_key) { 'fake_api_key_123' } let(:test_domain) { 'test.mydomain.com' } before do # 替换配置,避免硬编码敏感信息 allow(Rails.application.credentials).to receive(:mailgun_api_key).and_return(test_api_key) allow(Rails.application.credentials).to receive(:mailgun_domain).and_return(test_domain) end it 'sends POST request to Mailgun with correct parameters' do # 拦截Mailgun的API请求 stub_request(:post, "https://api:#{test_api_key}@api.mailgun.net/v3/#{test_domain}/messages") .with( body: { from: "Excited User <mailgun@#{test_domain}>", to: recipient_email, subject: "Hello", text: "Testing some Mailgun awesomness!" } ) .to_return(status: 200, body: '', headers: {}) # 调用Service described_class.new(recipient_email).call # 验证请求已发送 expect(WebMock).to have_requested(:post, "https://api:#{test_api_key}@api.mailgun.net/v3/#{test_domain}/messages") .with(body: hash_including(to: recipient_email)) end it 'handles API errors properly' do stub_request(:post, "https://api:#{test_api_key}@api.mailgun.net/v3/#{test_domain}/messages") .to_return(status: 400, body: '{"error": "Invalid recipient"}', headers: {}) # 根据你的Service错误处理逻辑调整,比如预期抛出异常 expect { described_class.new(recipient_email).call }.to raise_error(RestClient::BadRequest) end end
3. 测试控制器
控制器测试需要验证触发动作时,是否正确调用了SendMailService。
创建spec/controllers/your_target_controller_spec.rb(替换为实际控制器名):
require 'rails_helper' RSpec.describe YourTargetController, type: :controller do let(:recipient_email) { 'user@example.com' } it 'triggers SendMailService with the provided email' do # 模拟Service调用,无需实际执行发送逻辑 expect(SendMailService).to receive(:new).with(recipient_email).and_call_original expect_any_instance_of(SendMailService).to receive(:call) # 发送请求到控制器对应动作,示例为POST请求 post :send_email, params: { email: recipient_email } # 验证响应状态(根据你的控制器逻辑调整) expect(response).to have_http_status(:ok) end end
注意事项
- 不要在测试中硬编码API密钥和域名,用Rails credentials或环境变量管理,测试时替换为模拟值
- 可根据实际需求扩展测试场景,比如多收件人、自定义邮件内容、附件处理等
- 如果Service包含异常捕获、日志记录等逻辑,需要补充对应测试用例
内容的提问来源于stack exchange,提问作者badruz
相关产品推荐
相关产品推荐

