Testing on Google AppEngine (Python SDK)

Testing in Python and Django is pretty straight forward. However I wanted to write tests that assert email sending, URL fetching and other external sources. Making sure the intended code is executed and allowing me to write fuller tests.

These external actions are accessed through Google’s API, and there are some posts about how to test on Google AppEngine.

Here is an example by AppEngine Fan where he uses Mocker to mock out the external API calls. An approach that shows the power of the mocking library, but to my taste it results in too much code, and too much details about the mocking framework in the test making it harder to read. This ties back to a previous post I wrote about testing without Mocks.

What I wanted was some way to keep my original code intact and still have a pretty self explanatory test.

After some more research I found out that all API calls in the Python SDK are done through a proxy map. Allowing you to replace the behavior of AppEngine with your own, stubbed behavior. This method is used in this example (that still uses the mocking framework), and also this post on the user group was that location where I first noticed it.

This made me dig through the source code available in the SDK about how exactly this stub map worked. What I noticed was that if you started using the stub map, you needed to setup all the stubs.

As far as I could tell there was not means to replace just a single stub and let the map remain otherwise intact. Which was a bit of a trouble for me. One of the reasons I researched it was because I didn’t want to have tons of setup code in my tests.

Since my test code is important I thought I’d show how I want my tests to look like.

Requirements for good test-code:

  • Easy to read (Arrange-Act-Assert,Minimal setup code in the test)
  • Fast execution
  • non-fragile (black box testing the most external interface accessible for testing)

I want specific events in JS-Analytics to send an email to the administrators of JS-Analytics. The use case is covered with testing, but I wanted to add a test for this new requirement.

Here is what the test looks like:

 def test_given_a_new_project_an_email_is_sent_informing_the_admins(self):
	request = HttpRequest()
	request.user = User(username="…", user=users.User("…"))
    request.method = "POST"
    request.POST = {"title":"test"}
    index(request)
    self.assertEqual("project created", self.getMessages()[0].subject())

As you can see I wish to use the Log pattern for test sent messages. This allows me to check the sent messages in order. There is a method that allows me to access a copy of all sent emails, with their complete structure. Allowing me to assert different aspects of the emails.

To support this I created a base-class that adds the behavior I want as setup code. This setup code is generic and only specific for AppEngine aspects of the code. Here is the structure:

image

The base-class called ServiceTest sets up the stub map. I added two stubs that change the behavior from the normal stubs. These add support for setting content that will be accessed through the URLFetch service, and the logging of email messages.

Since no call ever cross the service boundary to actually do anything, the execution time isn’t compromised.

Here is an example of the setContent usage:

 def test_fetching_arrangement_example(self):
 	self.setResponse("http://url-to-be-fetched", "fake-content")
    request = HttpRequest()
    result = view_that_does_fetching(request)
    self.assertEqual(result.content, "fake-content")

As you can see its pretty straight forward to Arrange the which content should be returned where.

This structure should be so generic that anyone could use it, so I added a copy of my base-class free to use by others.