2011-02-02 66 views
1

我有一个Rails应用程序,我正在实施Twilio SMS API,并且我对如何测试驱动器的设计感到有些遗憾。使用第三方邮件的Rails TDD?

开始我刚做了一个模型,它是一个封装了twilio API的SMS邮件程序,我希望能够测试它并确保功能不会使用SMS信用或用测试文本消息轰击某人。

我知道如何实现API并让它在代码中工作,但我需要帮助的是实际测试代码以确保它能够正常工作并防止将来发生破坏。有谁能提供一些建议吗?

谢谢!

回答

2

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

将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 

这让我写测试专注于我的业务逻辑,这是我要搞砸了的东西。例如,如果我想要测试一些方法send_reminder(客户端),它发送一个短信:

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 

现在我测试的实际风险,我补充说,这是我搞砸了提醒。 send_reminder。另一方面,包装应该接近无风险。

+1

我认为这是一个不好的模式把在执行相关测试代码。 – 2011-02-02 18:23:20

1

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

使用外部API可能会非常棘手。一种选择是嘲笑你知道会对你有用的事情或对你期待的回应的反应,但这显然可能有点脆弱。另一种选择是看看VCR之类的东西。这将记录对外部API的调用,并在您再次调用时再次播放。

4

你可以使用我已经测试过的gem Twilio.rb,然后在你的测试中嘲笑它,与摩卡

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

你的单元测试不应该打外部服务,他们应该总是被嘲笑。这从单元测试的一般原则可以看出,测试不应该扩展被测试对象的类边界,并且合作者对象应该被模拟/存根。

希望这会有所帮助!

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

1

您可能不需要测试twiliolib的代码,但是如果您不想存储twiliolib的方法,那么您可以使用FakeWeb gem来定义指定请求的响应。

史蒂夫·类似提到的,我刚刚踩灭了请求,在与摩卡:

# 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