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

时间:2011-02-02 16:31:59

标签: ruby-on-rails tdd twilio

我有一个rails应用程序,我正在实现Twilio SMS API,我对如何测试驱动器设计感到有点迷失。

首先,我刚刚创建了一个SMS邮件模型,它将封装twilio API,我希望能够测试它并确保功能,而不会使用短信或使用测试文本消息轰炸某人。

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

谢谢!

5 个答案:

答案 0 :(得分:4)

您可以使用已经过测试的我的宝石Twilio.rb,然后在您的测试中模拟它,例如与摩卡

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

您的单元测试不应该打击外部服务,它们应该始终被嘲笑。这是从单元测试的一般原则得出的结果,即测试不应该扩展被测试对象的类边界,并且应该模拟/存根协作对象。

希望这有帮助!

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

答案 1 :(得分:2)

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

尽可能在业务逻辑类中包装API,并主要测试业务逻辑。例如,在我的系统中,SMSes被发送出Reminder类。代码看起来像这样:

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。另一方面,包装纸应该接近无风险。

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

与史蒂夫提到的类似,我只是用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