Testing

Ferris provides utilities to test your application using the nose test runner.

Installing the nose plugin

FerrisNose is a nose plugin that allows you to run isolated Google App Engine tests. Install it via pip:

pip install ferrisnose

Note

You may have to run this with sudo on Linux.

Running tests

To run tests just use nose:

nosetests --with-ferris tests

Warning

Be sure to specify a path or nose will try to discover all tests. We only need the test cases in /app/tests.

Note

You may need to tell the plugin where to find your appengine directory. You can specify using --gae-sdk-path:

nosetests --with-ferris --gae-sdk-path /home/user/google_appengine tests

Tip

Some libraries, especially ndb, do a lot of debug logging. If these logs are getting in the way of figuring out why your tests are failing, specify --logging-level INFO.

Testing recommendations

It’s recommend to focus on testing the business logic of your application and not so much the glue that binds things together. Therefore, it’s typical in a cloud endpoints application to test your models and any service layers around the models and not to spent too much effort testing your API services as they are mostly just glue. However, it is important to test more complicated translations between models and messages.

Mocking API calls

Google has an excellent guide on mocking API calls.

Writing tests for models

Models and other parts of the application that don’t involve HTTP/WSGI (such as services) can be tested using AppEngineTest.

class ferrisnose.AppEngineTest(methodName='runTest')

Basic class from which all app engine test cases can inherit from. Handles setting up the testbed and provides utilities to log in users and run deferred tasks.

Here is a simple example:

from app.cats.models import Cat
from ferrisnose import AppEngineTest

class CatTest(AppEngineTest):
    def test_herding(self):
        Cat(name="Pickles").put()
        Cat(name="Mr. Sparkles").put()

        assert Cat.query().count() == 2

Writing tests for web request handlers

AppEngineWebTest exposes a webtest instance so you can simulate a full web application. This is useful you testing any web request handlers you have in your applications.

class ferrisnose.AppEngineWebTest(methodName='runTest')

Provides a complete app engine testbed as well as a webtest instance available at self.testapp. You can add routes using self.add_route or add a ferris controller using self.add_controller.

You can easily add routes to testapp use add_route() and add_routes().

AppEngineWebTest.add_route(r)
AppEngineWebTest.add_routes(rs)

Here’s an example of writing a test case:

from app.cats import cats_handler
from ferrisnose import AppEngineWebTest

class CatsTest(AppEngineWebTest):
    def test_herding_method(self):
        self.add_routes(cats_handler.webapp2_routes)

        r = self.testapp.get('/cats')

        assert "Pickles" in r

Writing tests for cloud endpoints services

EndpointsTest makes it easier to test endpoints services. It handles setting up the proper environment as well as configuring a webtest instance.

class ferrisnose.EndpointsTest(methodName='runTest')

Provides an environment for testing Google Cloud Endpoints Services.

To add services to be tested use add_service().

EndpointsTest.add_service(*args)

Add the given service(s) to the testbed.

Note

No additional services can be added after getting the testapp

To login a user so that endpoints.get_current_user returns that user, use login().

EndpointsTest.login(email)

To invoke a service’s method, use invoke(). Note that you must use ClassName.method_name.

EndpointsTest.invoke(service_and_method, data=None, **kwargs)

Call an endpoint service method with the provided data. This will return the result of the method as a dictionary. This accepts additional parameters as post_json method from webtest.

Example::
result = self.invoke(‘GuestbookService.insert’, {‘content’: ‘Hello!’}) assert result[‘content’] == ‘Hello!’

A complete example:

from ferrisnose import EndpointsTest
from app.guestbook import guestbook_service


class TestGuestbook(EndpointsTest):

    def test_api(self):
        self.login("test@example.com")
        self.add_service(guestbook_service.GuestbookService)

        resp = self.invoke('GuestbookService.insert', {
            "content": "hello!"
        })

        assert resp['content'] == 'hello!'
        assert resp['author']['email'] == 'test@example.com'

        resp = self.invoke('GuestbookService.list')

        assert len(resp['items']) == 1
        assert resp['items'][0]['content'] == 'hello!'