Rails TDD 使用第 3 方邮件程序?

发布于 2024-10-15 12:08:32 字数 234 浏览 5 评论 0原文

我有一个 Rails 应用程序,正在其上实现 Twilio SMS API,但我对如何测试驱动我的设计有点迷失。

首先,我刚刚制作了一个 SMS 邮件程序模型,它将封装 twilio API,我希望能够测试它并确保其功能,而不会耗尽 SMS 积分或用测试短信轰炸某人。

我知道如何实现 API 并使其在代码中工作,但我需要帮助的是实际测试代码以确保其工作并防止将来出现损坏。有人可以提供一些建议吗?

谢谢!

I have a rails application that I am implementing the Twilio SMS API on, and I am a bit lost on how to test drive my design.

To start I've just made a model that is an SMS mailer that will encapsulate the twilio API and I want to be able to test it and ensure functionality without using up SMS credits or bombarding someone with test text messages.

I know how to implement the API and get it working in the code but what I need help with is actually testing the code to make sure it works and prevent breakage in the future. Could anyone provide some advice?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

谈下烟灰 2024-10-22 12:08:32

您可以使用我的 gem Twilio.rb,它已经经过测试,然后在您的测试中模拟它,例如使用 mocha

Twilio::SMS.expects(:create).with :to => '+19175551234', :from => '+12125551234', :body => 'this is easy!'

您的单元测试永远不应该访问外部服务,它们应该始终被模拟。这是遵循单元测试的一般原则的,即测试不应扩展被测试对象的类边界,并且协作者对象应被模拟/存根。

希望这有帮助!

https://github.com/stevegraham/twilio-rb

You could use my gem Twilio.rb, which is already tested, and then mock it out in your tests, e.g. with mocha

Twilio::SMS.expects(:create).with :to => '+19175551234', :from => '+12125551234', :body => 'this is easy!'

Your unit tests should never hit external services, they should always be mocked. This is follows from a general principle of unit testing that tests should not extend the class boundary of the object being tested and collaborator objects should be mocked/stubbed.

Hope this helps!

https://github.com/stevegraham/twilio-rb

居里长安 2024-10-22 12:08:32

我在测试以及测试 Twilio 应用程序方面的经验是,您进行测试是为了消除您添加的风险。您需要使用 Twilio gem,而不是根据他们的 REST 滚动您自己的 SMS 代码终点:这可以最大限度地降低风险。

将 API 尽可能薄地包装在业务逻辑类中,并主要测试业务逻辑。例如,在我的系统中,短信是从提醒类发送的。代码看起来像这样:

class SomeWrapperClass
  if (RAILS_ENV == "testing")
    @@sent_smses = []
    cattr_accessor :sent_smses
  end

  def send_a_message(to, from, message, callback_url = nil)
    unless RAILS_ENV == "testing"
      Twilio::SMS.message(to, from, message, callback_url)
    else
      @@sent_smses << {:to => to, :from => from, :message => message, :callback_url => callback_url}
    end
  end
end

这让我可以编写专注于我的业务逻辑的测试,而这正是我要搞砸的东西。例如,如果我想测试某种发送 SMS 消息的方法 send_reminder(client):

test "sends reminder to client" do
  SomeWrapperClass.sent_smses = []
  client = clients(:send_reminder_test_case)
  Reminder.send_reminder(client)
  sent_message = SomeWrapperClass.sent_smses.last
  assert !sent_message.blank?, "Sending a reminder should fire an SMS to client."
  assert sent_message.index(client.name) >= 0, "Sending a reminder should fire an SMS with the client's name in it.
  ...
end

现在我正在测试我添加的实际风险,即我搞砸了 Reminder.send_reminder。另一方面,包装纸应该接近无风险。

My experience with testing, and with testing Twilio applications, is that you test to eliminate risk you add. You'll want to use the Twilio gem rather than rolling your own SMS code against their REST endpoint: this minimizes the amount of risk.

Wrap the API as thinly as possible in your business logic class, and test primarily the business logic. For example, in my system, SMSes get sent out of the Reminder class. The code looks something like this:

class SomeWrapperClass
  if (RAILS_ENV == "testing")
    @@sent_smses = []
    cattr_accessor :sent_smses
  end

  def send_a_message(to, from, message, callback_url = nil)
    unless RAILS_ENV == "testing"
      Twilio::SMS.message(to, from, message, callback_url)
    else
      @@sent_smses << {:to => to, :from => from, :message => message, :callback_url => callback_url}
    end
  end
end

This lets me write tests focusing on my business logic, which is the stuff I'm going to screw up. For example, if I want to test some method send_reminder(client) which sends a SMS message:

test "sends reminder to client" do
  SomeWrapperClass.sent_smses = []
  client = clients(:send_reminder_test_case)
  Reminder.send_reminder(client)
  sent_message = SomeWrapperClass.sent_smses.last
  assert !sent_message.blank?, "Sending a reminder should fire an SMS to client."
  assert sent_message.index(client.name) >= 0, "Sending a reminder should fire an SMS with the client's name in it.
  ...
end

Now I'm testing the actual risk I've added, which is that I'm screwing up Reminder.send_reminder. The wrapper, on the other hand, should be close to risk-free.

我喜欢麦丽素 2024-10-22 12:08:32

显然,尽可能多地分离逻辑。通过这样做,您可以尽可能地测试其他所有内容,然后只保留对需要测试的外部 API 的调用。

使用外部 API 可能会很棘手。一种选择是模拟对您知道对您有用的东西的响应或对您期望的响应的响应,但这显然有点脆弱。另一种选择是查看类似 VCR 的内容。这将记录一次对外部 API 的调用,并在您再次调用时再次播放。

Obviously separate as much of the logic as possible. By doing this you can test everything else around as much as possible and then only leave the calls to the external API needing tests.

Working with external API's can be tricky. One option is to mock the response to something that you know will work for you or to the response you would expect, this can obviously be a bit brittle though. Another option is to look at something like VCR. This will record the call to the external API once and play it back again whenever you call it again.

汹涌人海 2024-10-22 12:08:32

这家伙似乎已经开始解决你的问题: https://github.com/arfrank/Fake-Twilio -API

This guy seems to have started solving your problem: https://github.com/arfrank/Fake-Twilio-Api

凉宸 2024-10-22 12:08:32

您可能不需要测试 twiliolib 的代码,但如果您不想存根 twiliolib 的方法,您可以使用 FakeWeb gem,在其中定义指定请求的响应。

与 Steve 提到的类似,我只是用 mocha 删除了请求:

# In Twilio initializer
TWILIO_ACCOUNT = Twilio::RestAccount.new(TWILIO_CONFIG[:sid], TWILIO_CONFIG[:token])

# In a test helper file somewhere
class ActiveSupport::TestCase
  # Call this whenever you need to test twilio requests
  def stub_twilio_requests
    # Stub the actual request to Twilio
    TWILIO_ACCOUNT.stubs(:request).returns(Net::HTTPSuccess.new(nil, nil, nil).tap { |n| 
      n.stubs(:body).returns("<?xml version=\"1.0\"?>\n<TwilioResponse></TwilioResponse>\n") 
    })
  end
end

You probably don't need to test twiliolib's code, but if you don't want to stub twiliolib's methods you could use the FakeWeb gem, where you define the response for specified requests.

Similar to Steve mentioned, I just stub out the request with mocha:

# In Twilio initializer
TWILIO_ACCOUNT = Twilio::RestAccount.new(TWILIO_CONFIG[:sid], TWILIO_CONFIG[:token])

# In a test helper file somewhere
class ActiveSupport::TestCase
  # Call this whenever you need to test twilio requests
  def stub_twilio_requests
    # Stub the actual request to Twilio
    TWILIO_ACCOUNT.stubs(:request).returns(Net::HTTPSuccess.new(nil, nil, nil).tap { |n| 
      n.stubs(:body).returns("<?xml version=\"1.0\"?>\n<TwilioResponse></TwilioResponse>\n") 
    })
  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文