NoseGAE: nose plugin for Google App Engine testing
Python Shell
Switch branches/tags
Nothing to show
Clone or download
Pull request Compare This branch is 1 commit ahead, 75 commits behind Trii:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
bin
docs
support
.gitignore
AUTHORS
CHANGELOG
NOTES
fixt.py
nosegae.py
readme.rst
run_tests.sh
setup.cfg
setup.py
tests.rst
unit_tests.py

readme.rst

NoseGAE: Test support for Google Application Engine

.. fixtures :: fixt

Overview

NoseGAE is a nose plugin that makes it easier to write functional and unit tests for Google App Engine applications.

When the plugin is installed, you can activate it by using the --with-gae command line option. The plugin also includes an option for setting the path to the Google App Engine python library, if it is not in the standard location of /usr/local/google_appengine.

What does it do?

Functional tests

The plugin sets up the GAE development environment before your test run. This means that you can easily write functional tests for your application without having to actually start the dev server and test over http. Note however that this kind of testing requires that your application be a wsgi application.

Consider a simple hello world wsgi application:

And a simple functional test suite for the application:

The important part to note is the application() function that returns the application. That function provides a way get the application under test and call it directly, without having to pass through the dev app server. And that's all you need to do for basic functional testing.

.. shell :: nosetests -v --with-gae
   :cwd: support/helloworld
   :post: cleanup
   :stderr:

   test.test_index ... ok
   <BLANKLINE>
   ----------------------------------------------------------------------
   Ran 1 test in ...s
   <BLANKLINE>
   OK

Unit tests

Functional tests are only one kind of test, of course. What if you want to write unit tests for your data models? Normally, you can't use your models at all outside of the dev environment, because the Google App Engine datastore isn't available. However, since the NoseGAE plugin sets up the development environment around your test run, you can use models directly in your tests.

Consider a simple models.py file that includes some doctests:

Without NoseGAE, the doctests fail.

.. shell :: nosetests -v --with-doctest
   :cwd: support/pets
   :post: cleanup
   :stderr:

   Failure: ImportError (No module named google.appengine.ext) ... ERROR
   <BLANKLINE>
   ======================================================================
   ERROR: Failure: ImportError (No module named google.appengine.ext)
   ----------------------------------------------------------------------
   Traceback (most recent call last):
   ...
   ImportError: No module named google.appengine.ext
   <BLANKLINE>
   ----------------------------------------------------------------------
   Ran 1 test in ...s
   <BLANKLINE>
   FAILED (errors=1)

With NoseGAE, they pass.

.. shell :: nosetests -v --with-doctest --with-gae
   :cwd: support/pets
   :post: cleanup
   :stderr:

   Doctest: models.Pet ... ok
   <BLANKLINE>
   ----------------------------------------------------------------------
   Ran 1 test in ...s
   <BLANKLINE>
   OK

Realism in testing

Besides the dev appserver and the datastore, the main sticking point for testing Google App Engine applications is the highly restrictive runtime environment. When you test without NoseGAE, tests that should fail (because the tested code will fail when run inside the Google App Engine) may pass.

For instance, consider an app that uses the socket module, like this one:

With a simple functional test:

This test will pass when run outside of the Google App Engine environment.

.. shell :: nosetests -v
   :cwd: support/bad_app
   :post: cleanup
   :stderr:

   test.test_index_calls_gethostbyname ... ok
   <BLANKLINE>
   ----------------------------------------------------------------------
   Ran 1 test in ...s
   <BLANKLINE>
   OK

When run with NoseGAE, it will fail, as it should.

.. shell :: nosetests -v --with-gae
   :cwd: support/bad_app
   :post: cleanup
   :stderr:

   test.test_index_calls_gethostbyname ... ERROR
   <BLANKLINE>
   ======================================================================
   ERROR: test.test_index_calls_gethostbyname
   ----------------------------------------------------------------------
   Traceback (most recent call last):
   ...
   <BLANKLINE>
   ----------------------------------------------------------------------
   Ran 1 test in ...s
   <BLANKLINE>
   FAILED (errors=1)

It is important to note that only application code is sandboxed by NoseGAE. Test code imports outside of the sandbox, so your test code has full access to the system and available python libraries, including the Google App Engine datastore and other Google App Engine libraries.

For this reason, file access is not restricted in the same way as it is under GAE, because it is impossible to differentiate application code file access from test code file access.

However, this means that some things like profiling or Nose's --coverage option will not work without some hacks. If you run into these issues you can pass in the option --without-sandbox to turn off the GAE import hook simulation.

Developers

To work on NoseGAE you'll need some dependencies. Unfortunately, the Google App Engine SDK makes virtualenv unusable so you either have to pollute your global Python or build a custom Python 2.5 or Python 2.7 interpreter for use with NoseGAE (recommended).

  • Install setuptools
  • easy_install Nose trestle WebTest

Run the tests:

# Set this to the top level dir, the one with the bin dir in it:
export PY25_ROOT=/usr/local/python2.5.5-app-engine
./run_tests.sh

Alternate installation with pip:

  • pip install nose nose-gae
  • export PY25_ROOT=/usr/local/python2.5.5-app-engine
    OR
  • export PY27_ROOT=/usr/local/python2.7.8-app-engine

Alternate installation in virtualenv with pip:

  • Navigate to the directory in which you have your virtual environment set up (usually the root of the project), then to the bin folder, then ./pip install nose, then nosegae
  • E.G. /home/user/location/of/your/project/root/env/bin
Downloading/unpacking nose

Downloading nose-1.3.4.tar.gz (277kB): 277kB downloaded Running setup.py egg_info for package nose

no previously-included directories found matching 'doc/.build'
Installing collected packages: nose

Running setup.py install for nose

no previously-included directories found matching 'doc/.build' Installing nosetests script to /home/user/location/of/your/project/root/env/bin Installing nosetests-2.7 script to /home/user/location/of/your/project/root/env/bin

Successfully installed nose Cleaning up...

  • ./pip install nosegae
Downloading/unpacking nosegae
Downloading NoseGAE-0.2.1.tar.gz Running setup.py egg_info for package nosegae

Requirement already satisfied (use --upgrade to upgrade): nose>=0.10.1 in /home/user/location/of/your/project/root/env/lib/python2.7/site-packages (from nosegae) Installing collected packages: nosegae

Running setup.py install for nosegae

Successfully installed nosegae Cleaning up...