Testing telephony applications is a lot like testing web applications. Much of the toolchain is the same; inside Adhearsion we use rspec, cucumber, guard and simplecov. For testing apps we also use tools like FactoryGirl, fakeweb and vcr. The fundamentals of testing Ruby classes is of course the same: construct a set of test inputs, set up expectations for outputs and behavior, then run the code.
However there are some important differences, especially with how you think about testing your application:
Unit testing is attempting to test an individual unit in isolation. You will construct a set of inputs, define expectations (or mocks, if necessary) on any external behavior, and validate the result returned. Typically a unit is a single method within a class.
For example, given a class that looks like this:
class MyApp
def double(in)
in * in
end
endYou would want to have the following tests:
Beyond testing basic functionality it becomes important to test how your calls will interact with your application. Most of that interaction happens within Call Controllers. Because Call Controllers are simply classes that inherit from the Adhearsion::CallController class, testing these is just like testing any other Ruby class. However you will likely want to mock out the methods where the telephone call interacts with the framework, such as #ask, #play, #answer and #hangup. For example, a Call Controller like this:
class MyApp < Adhearsion::CallController
FACTOR = 2
def run
answer
result = ask "How much is #{FACTOR} times #{FACTOR}?"
if result.response == double FACTOR
play "tt-weasels"
end
hangup
end
endYou would want to have the following in your tests (these would be satisfied across several individual tests):
#answer was invoked first#ask was called with the correct question string ("How much is 2 times 2?")#ask to pretend that the caller pressed a DTMF digit#play was called with "tt-weasels" only if the mocked result is "4"#hangup was invoked lastA sample controller test might look something like this:
require 'spec_helper'
describe MyController do
let(:mock_call) { mock 'Call', to: '1112223333', from: "2223334444" }
let(:metadata) { {} }
subject { MyController.new mock_call, metadata }
its(:metadata) { should eq({}) }
endThis is a skeleton for controllers that will pass with a controller generated using Adhearsion's generator utility.
Please see the documentation on the Plugins page.
Integration testing is the attempt to test the interaction between two or more pieces of an application. This may even be an entire application end-to-end. The goal then is to provide your inputs and measure their results without making assertions on how the code makes them happen. Said another way: the implementation details are unimportant, but the observable behavior is. For example, you may describe test inputs like this:
This syntax may sound like Cucumber, and it is. Cucumber is one of the tools used in setting up integration tests.
Here are some of the other tools often used to effect integration testing: