Unit Testing Your Twilio App Using Python’s Flask and Nose
Time to read: 4 minutes
“We’re sorry. An application error has occurred. Goodbye.”
Rage wells inside you familiar to the impulse hearing the dog laugh at you in Duck Hunt. You open the Twilio App Monitor and find the culprit – a fat fingered typo on your Dial verb.
Cue the sad trombone.
It happens to all of us. And when you’re iterating on your Twilio code, the wash-rinse-repeat cycle of changing code, deploying to a web server and manually testing on your phone can become tiresome quickly.
One technique I use to reduce this frustration is writing unit tests against my Twilio webhook endpoints as I work on my app. Utilizing a web framework’s test client to write these tests quickly helps keep my focus on the app I’m trying to write and the knucklehead errors that produce the Duck Hunt experience to a minimum.
What You’ll Learn
In this post, we’ll show that technique in action with Flask, my go-to framework for writing Twilio apps in Python.
- How to write a simple Twilio Conference endpoint with Flask
- Write a unit test with Nose for that endpoint
- Expand that unit test into a test case we can reuse for all our Twilio apps
- Then show how that reusable test case can be applied to more complex flows.
What You’ll Need
- Sign up for a free Twilio account
- Install the Twilio Python module
- Install the Flask web microframework
- Install the Nose testing framework
Let’s Cut Some Code
To start, we’ll open a text editor in our Python environment with the Twilio and Flask modules installed and clack out a simple app that will create a Twilio Conference room using the verb and the noun.
Here’s a quick cut in a file we’ll name app.py:
Now Let’s Test It
I think this code might be right, but let’s make sure by writing a quick unit test. To do this, we’ll open another file called test_app.py. In that file, we’ll import our app and define a unit test using unittest in the Python standard library. We’ll then use the Flask test client to make a test request to the app and see if the app throws an error.
We then run the unit test using Nose By issuing the following command, Nose will go through our unit test file, find all TestCase objects and execute each method prefixed with test_:
nosetests -v test_app.py
Oh biscuits – looks like we got a bug.
D’oh. The name of the TwiML noun for conferencing isn’t “Conf” but “Conference.” Let’s revisit our app.py file and correct the bug.
Now with the Conference line corrected, we can rerun our tests with the same command as above:
Awesome. And we didn’t have to pick up our phones to figure out the error.
Now Let’s Make Sure This Code Does What We Want
Making sure the code doesn’t throw an error is a good first step, but we also want to make sure our Twilio app performs the way we intend. First we need to check that the app returns a response that Twilio can interpret, make sure it is creating a valid Dial verb and finally that the Dial points to the correct Conference room.
To help, we’ll use ElementTree, an XML parser from the Python standard library. This way we can interpret the TwiML response the same way Twilio would. Let’s look how we would add this to test_app.py:
Now run both tests using Nose:
Killer. Now we’re confident this app is doing what we want in addition to returning an appropriate response.
DRYing Up Our Tests For Reuse
It’s great that we know our new Twilio endpoint works without needing to test it manually, but Twilio apps rarely use a single webhook endpoint. As our application grows in complexity we can see these two tests are going to repeat a whole lot of code. Let’s see if we can refactor our tests into a generic test case we can use for any Twilio webhook endpoints we build in the future.
To do this, we’ll create a generic TwiMLTest class and leverage the built-in setUp() method to instantiate our Flask test client automatically with every test.
Great start – now let’s create a helper method that accepts a response and does the basic validation that it is working TwiML.
Finally, instead of creating a new POST request with every test, let’s create two more helper methods that will create Twilio requests for calls and messages that we can easily extend with custom parameters. Let’s add a new class to test_app.py.
Excellent – now we can refactor our original tests for the conference using the new helper methods, making the tests much shorter:
Perfect – let’s run our tests using Nose and see if we’re golden.
And all is good with the world.
Go Forth And Test
With our generic test case for Twilio apps, now writing tests is quick and simple. We wrote a quick Conferencing app, tested it using Nose, and then refactored those tests into a generic case you can use with all your apps. By using this test case, testing our Twilio apps built on Flask can be fast and painless, reducing both the amount of time spent manually testing with your phone and the number of times you have to hear the dreaded “Application Error” voice.
Because no likes to hear this on the other end of the phone.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.