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()
self.output(1, "%s module: running tests" % module) runner.run(dtest, clear_globs=True, out=sys.stdout.write) if hasattr(mod, "run_tests") and callable(mod.run_tests): self.output(1, "%s module: running tests" % module) try: mod.run_tests(verbosity_level) except Exception, e: log_error(module, "Exception running tests", ''.join(traceback.format_exception(*sys.exc_info())[1:])) continue # Unless we're using SQLite, remove the test database to clean up after # ourselves. Connect to the previous database (not the test database) # to do so, because it's not allowed to delete a database while being # connected to it. if settings.DATABASE_ENGINE != "sqlite3": db.close() settings.DATABASE_NAME = old_database_name cursor = db.cursor() self.output(1, "Deleting test database") try: db.connection.autocommit(1) except AttributeError: pass else: time.sleep(1) # To avoid "database is being accessed by other users" errors. cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME) # Display output. if error_list: for d in error_list: print