You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:35:17