1

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

首先,我刚刚创建了一个模型,它是一个封装 twilio API 的 SMS 邮件程序,我希望能够对其进行测试并确保其功能,而不会用完 SMS 积分或用测试文本消息轰炸某人。

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

谢谢!

4

5 回答 5

4

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

Twilio::SMS.expects(:create).with :to => '+19175551234', :from => '+12125551234', :body => '这很简单!'

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

希望这可以帮助!

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

于 2011-02-02T18:02:00.287 回答
2

我的测试经验以及测试 Twilio 应用程序的经验是,您进行测试以消除添加的风险。您将希望使用Twilio gem,而不是针对他们的 REST 端点滚动您自己的 SMS 代码:这可以最大限度地降低风险。

尽可能将 API 封装在业务逻辑类中,并主要测试业务逻辑。例如,在我的系统中,SMS 是从 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。另一方面,包装器应该接近无风险。

于 2011-02-02T18:10:38.613 回答
1

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

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

于 2011-02-02T16:49:44.343 回答
1

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

于 2011-02-02T18:08:13.557 回答
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
于 2011-02-02T19:01:14.460 回答