Вопрос

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!

Это было полезно?

Решение

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.

Другие советы

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

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.

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

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top