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!'