我有一个rails应用程序,我正在实现Twilio SMS API,我对如何测试驱动器设计感到有点迷失。
首先,我刚刚创建了一个SMS邮件模型,它将封装twilio API,我希望能够测试它并确保功能,而不会使用短信或使用测试文本消息轰炸某人。
我知道如何实现API并使其在代码中运行,但我需要帮助的是实际测试代码以确保它有效并防止将来发生破坏。有人可以提供一些建议吗?
谢谢!
答案 0 :(得分:4)
您可以使用已经过测试的我的宝石Twilio.rb,然后在您的测试中模拟它,例如与摩卡
Twilio::SMS.expects(:create).with :to => '+19175551234', :from => '+12125551234', :body => 'this is easy!'
您的单元测试不应该打击外部服务,它们应该始终被嘲笑。这是从单元测试的一般原则得出的结果,即测试不应该扩展被测试对象的类边界,并且应该模拟/存根协作对象。
希望这有帮助!
答案 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