def test_app(app): """test_app(app) Tests the application app: - a clean sqlite in-memory database is create - the applications models are installed - the fixtures in path-to-app/fixtures/*.yml are created - settings.ROOT_URLCONF is pointed at the applications urls-module - the tests in the tests-module are run with doctest.testmod given the fixtures and a browser-instance as globals """ # Import application module if '.' in app: i = app.rfind('.') app_name = app[i+1:] else: app_name = app module = __import__(app, None, None, ['*']) # Reinitialize database db.db.real_close() # this is in effect a 'drop database' with a sqlite :memory: database management.init() # Install models for model in module.models.__all__: management.install(meta.get_app(model)) # Load fixtures files = os.path.join(os.path.dirname(module.__file__), 'fixtures', '*.yml') fixtures = {} for yml in [ yaml.loadFile(f) for f in glob(files) ]: models = yml.next() for model, fixs in models.items(): model = meta.get_module(app_name, model) klass = model.Klass for name, kwargs in fixs.items(): obj = create_object(klass, kwargs) # Load object from database, this normalizes it. fixtures[name] = model.get_object(pk=obj.id) # Commit fixtures db.db.commit() # Munge django.conf.settings.ROOT_URLCONF to point to # this apps urls-module, settings.ROOT_URLCONF = app + '.urls' # Run tests module = __import__(app, None, None, ['tests']) tests = getattr(module, 'tests', None) if tests: globs = { 'browser': Browser(app), } globs.update(fixtures) doctest.testmod(tests, None, globs)
def run_tests(self): from django.conf import settings from django.core.db import db from django.core import management, meta # Manually set INSTALLED_APPS to point to the test app. settings.INSTALLED_APPS = (APP_NAME,) # Determine which models we're going to test. test_models = get_test_models() if self.which_tests: # Only run the specified tests. bad_models = [m for m in self.which_tests if m not in test_models] if bad_models: sys.stderr.write("Models not found: %s\n" % bad_models) sys.exit(1) else: test_models = self.which_tests self.output(0, "Running tests with database %r" % settings.DATABASE_ENGINE) # If we're using SQLite, it's more convenient to test against an # in-memory database. if settings.DATABASE_ENGINE == "sqlite3": global TEST_DATABASE_NAME TEST_DATABASE_NAME = ":memory:" else: # Create the test database and connect to it. We need autocommit() # because PostgreSQL doesn't allow CREATE DATABASE statements # within transactions. cursor = db.cursor() try: db.connection.autocommit(1) except AttributeError: pass self.output(1, "Creating test database") try: cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME) except: confirm = raw_input("The test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) if confirm == 'yes': cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME) cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME) else: print "Tests cancelled." return db.close() old_database_name = settings.DATABASE_NAME settings.DATABASE_NAME = TEST_DATABASE_NAME # Initialize the test database. cursor = db.cursor() self.output(1, "Initializing test database") management.init() # Run the tests for each test model. self.output(1, "Running app tests") for model_name in test_models: self.output(1, "%s model: Importing" % model_name) try: mod = meta.get_app(model_name) except Exception, e: log_error(model_name, "Error while importing", ''.join(traceback.format_exception(*sys.exc_info())[1:])) continue self.output(1, "%s model: Installing" % model_name) management.install(mod) # Run the API tests. p = doctest.DocTestParser() test_namespace = dict([(m._meta.module_name, getattr(mod, m._meta.module_name)) for m in mod._MODELS]) dtest = p.get_doctest(mod.API_TESTS, test_namespace, model_name, None, None) # Manually set verbose=False, because "-v" command-line parameter # has side effects on doctest TestRunner class. runner = DjangoDoctestRunner(verbosity_level=verbosity_level, verbose=False) self.output(1, "%s model: Running tests" % model_name) try: runner.run(dtest, clear_globs=True, out=sys.stdout.write) finally: # Rollback, in case of database errors. Otherwise they'd have # side effects on other tests. db.rollback()